Build · New

Popover

A small surface for one quick task, opened next to the control that asked for it.

Preview

Mirrored is the same English content laid out right to left: it separates a mirroring bug from a translation one.

Installation

SoonInstalling from the registry opens at launch. Until then the command below is what it will be.
npx shadcn@latest add @ritla/popover

Dependencies it brings: @base-ui/react, @phosphor-icons/react

Usage

import { Button } from "@/components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
<Popover>
  <PopoverTrigger render={<Button variant="outline" />}>Share</PopoverTrigger>
  <PopoverContent title="Share this report" description="Anyone with the link can view it.">
    …
  </PopoverContent>
</Popover>

Examples

Filter

A few choices and Apply (PopoverClose), which closes it and returns focus to the trigger. No close button here: Cancel and Esc are enough.

Sides

side: Bottom (default), Top, Start and End. Start and End follow the reading direction, so Start is on the right in Arabic, and the arrow always points at the trigger. Without room, it flips to the other side.

API reference

Popover

PropTypeDefaultDescription
open / defaultOpenbooleanTo control it from code.
onOpenChange(open, details) => voidWhen it opens or closes.

PopoverTrigger

PropTypeDefaultDescription
renderReactElementThe visible control: <Button … />.

PopoverContent

PropTypeDefaultDescription
titleReactNodeFigma's Title: what it's for; names the dialog.
descriptionReactNodeFigma's Description: one line under the title.
childrenReactNodeThe body: a field and a button, or a few choices.
side"bottom" | "top" | "start" | "end""bottom"Figma's Side. Flips when there isn't room.
align"start" | "center" | "end""center"Where it lines up along that side.
arrowbooleantrueThe arrow, pointing at the trigger.
closeButtonbooleantrueThe close button at the header's inline end.
closeLabelstring"Close" / «إغلاق»The close button's name.
sideOffsetnumber12Space between trigger and surface.
initialFocus / finalFocusRefObject<HTMLElement>Where focus starts and where it returns.

PopoverClose

PropTypeDefaultDescription
renderReactElementA control in the body that closes it: Apply, Done.

Accessibility

Keyboard

Keys are written for left-to-right. In right-to-left the arrow keys swap: the one pointing toward the reading direction moves forward.

KeyAction
EnterSpaceOn the trigger: opens it and moves focus to its first field, else its first control.
TabShift+TabBetween its controls. Focus isn't trapped: tabbing out closes it.
EscCloses it and returns focus to the trigger.

ARIA

  • A non-modal dialog (role="dialog") named by its title and described by its description.
  • The trigger has aria-expanded and aria-controls.
  • A click outside closes it; typing inside never does.
  • No popover inside another: use a Dialog for bigger tasks.

Arabic and RTL notes

Mirrors

  • Start and End: Start opens on the right in Arabic.
  • The close button sits at the header's inline end: on the left.
  • The arrow follows the side and points at the trigger in both directions.

Does not mirror

  • URLs, codes and IDs stay left to right.
  • Bottom and Top don't change.
Numerals
Numbers inside follow the numerals setting.
Arabic typography
Title label-16 Semibold, description label-14.
Mixed-direction text
It carries the trigger's direction and language into the portal, so an Arabic preview on an English page stays Arabic. A field with dir="ltr" keeps the whole link left to right.

All components ›