Skip to content

Popover

A small panel anchored to its trigger, for extra information or a few controls. The page stays usable while it’s open. For a task that needs full attention, use Modal.

Code
demo.tsx
import {Button, Popover} from '@earendil-works/elanor-react';

export default function PopoverDemo() {
  return (
    <Popover.Root>
      <Popover.Trigger render={<Button hierarchy="secondary" />}>Usage limits</Popover.Trigger>
      <Popover.Portal>
        <Popover.Positioner>
          <Popover.Popup>
            <Popover.Title>Monthly usage</Popover.Title>
            <Popover.Description>
              Usage resets on the first day of each month. Unused credits don't carry over.
            </Popover.Description>
          </Popover.Popup>
        </Popover.Positioner>
      </Popover.Portal>
    </Popover.Root>
  );
}

Usage

import {Popover} from '@earendil-works/elanor-react';

<Popover.Root>
  <Popover.Trigger />
  <Popover.Portal>
    <Popover.Positioner>
      <Popover.Popup>
        <Popover.Title />
        <Popover.Description />
        <Popover.Close />
      </Popover.Popup>
    </Popover.Positioner>
  </Popover.Portal>
</Popover.Root>;

The trigger opens the popover on click. Escape, clicking outside, or Popover.Close closes it and returns focus to the trigger.

Static rendering

On pages rendered on the server without React in the browser, use the static parts, and bind their behavior once the page has loaded:

<Popover.StaticRoot>
  <Popover.StaticTrigger />
  <Popover.StaticPositioner side="bottom" align="start" sideOffset={4}>
    <Popover.StaticPopup>
      <Popover.StaticTitle />
      <Popover.StaticDescription />
      <Popover.StaticClose />
    </Popover.StaticPopup>
  </Popover.StaticPositioner>
</Popover.StaticRoot>
import {createPopover, enhance} from '@earendil-works/elanor-react';

enhance({popover: createPopover});

The positioner is a native popover in the top layer. The behavior places it next to the trigger on any side, flipping when the other side has more room, and opens and closes it with the same states and animation as the React parts; Escape and a press outside close it, and focus moves to the first focusable element. Without the behavior, the browser opens it in the middle of the window. Give StaticRoot an id to open the popover from other buttons too, with popovertarget.

API

Popover.Root

Accepts Base UI Popover.Root props.

Popover.Trigger

Accepts Base UI Popover.Trigger props.

Popover.Portal

Accepts Base UI Popover.Portal props.

Popover.Positioner

Accepts Base UI Popover.Positioner props.

Popover.Popup

Accepts Base UI Popover.Popup props.

Popover.Title

Accepts Base UI Popover.Title props.

Popover.Description

Accepts Base UI Popover.Description props.

Popover.Close

Accepts Base UI Popover.Close props.

Popover.StaticRoot

A popover for pages without React in the browser; createPopover makes it work. Renders no element.

PropTypeDefaultDescription
idstring-The popover's id, so other buttons can open it with popovertarget. Generated by default.
childrenReactNode-

Also accepts HTML attributes and ref.

Popover.StaticTrigger

Renders <button>. Accepts its HTML attributes and ref.

Popover.StaticPositioner

The popover in the top layer, placed next to the trigger. Holds the StaticPopup.

PropTypeDefaultDescription
data-elanorstring-The page's own behaviors for this element, attached after the component's.
side'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start''bottom'
align'center' | 'start' | 'end''center'
sideOffsetExtract<BasePopover.Positioner.Props['sideOffset'], number>0

Renders <div>. Also accepts its HTML attributes and ref.

Popover.StaticPopup

Renders <div>. Accepts its HTML attributes and ref.

Popover.StaticTitle

Renders <h2>. Accepts its HTML attributes and ref.

Popover.StaticDescription

Renders <p>. Accepts its HTML attributes and ref.

Popover.StaticClose

Renders <button>. Accepts its HTML attributes and ref.