Skip to content

Popover

Non-modal panel anchored to a trigger, for extra controls or details. Open it with DialogTrigger.

Overlayv0.1.0experimentalWCAG 2.2 AAView spec
import { Button, Checkbox, Popover, PopoverTrigger } from "@rdloom/react";

export default function PopoverBasicExample() {
  return (
    <PopoverTrigger>
      <Button variant="secondary">Filters</Button>
      <Popover label="Filters">
        <div className="flex w-56 flex-col gap-3">
          <Checkbox defaultSelected>Active</Checkbox>
          <Checkbox>Archived</Checkbox>
        </div>
      </Popover>
    </PopoverTrigger>
  );
}

Installation

npx rdloom add popover

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/popover.json

Works, but without upgrade tracking.

Usage

import { Button, Checkbox, Popover, PopoverTrigger } from "@rdloom/react";

<PopoverTrigger>
  <Button variant="secondary">Filters</Button>
  <Popover label="Filters">
    <div className="flex w-56 flex-col gap-3">
      <Checkbox defaultSelected>Active</Checkbox>
      <Checkbox>Archived</Checkbox>
    </div>
  </Popover>
</PopoverTrigger>

With arrow

import { Button, Popover, PopoverTrigger } from "@rdloom/react";

export default function PopoverWithArrowExample() {
  return (
    <PopoverTrigger>
      <Button variant="secondary">What's new</Button>
      <Popover label="What's new" showArrow>
        <p className="w-60 text-sm">Data grids now support inline editing and pagination.</p>
      </Popover>
    </PopoverTrigger>
  );
}

Placements

import { Button, Popover, PopoverTrigger } from "@rdloom/react";

export default function PopoverPlacementsExample() {
  return (
    <div className="flex flex-wrap gap-3">
      {(["top", "bottom", "start", "end"] as const).map((placement) => (
        <PopoverTrigger key={placement}>
          <Button variant="secondary">{placement}</Button>
          <Popover label={`Placed ${placement}`} placement={placement} showArrow>
            <p className="text-sm">Placed {placement}</p>
          </Popover>
        </PopoverTrigger>
      ))}
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
labelrequired

Accessible name for the popover content.

stringnone
placement

Preferred side of the trigger. Flips when there isn't room.

"top" | "bottom" | "start" | "end""bottom"
showArrow

Shows an arrow pointing at the trigger.

booleanfalse
children

Popover content. A function receives close().

ReactNode | ((opts: { close: () => void }) => ReactNode)none

Accessibility

Role dialog, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Esc closes and returns focus to the trigger

Screen readers announce

  • Opening announces a dialog named by its label (Filters)
  • Its controls are reachable with Tab; Esc announces the trigger again

What your code must do

  • Has an accessible name
  • Focus moves into the popover on open

Guidelines

Use it when

  • Filters, quick settings or details related to a control

Avoid it when

  • Plain hints: use Tooltip
  • Blocking tasks: use Dialog

Don't

  • Opening on hover
  • Very long scrolling content

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-surface-raised
  • --rd-color-border-default
  • --rd-color-text-default
  • --rd-radius-overlay