An overlay positioned relative to a trigger.
There is no built-in way to create popovers in HTML. Popover helps achieve accessible popovers that can be styled as needed.
| Prop | Type | Default |
|---|---|---|
| Space | Opens the popover. | |
| Enter | Opens the popover. | |
| Tab | Moves focus to the next focusable element. | |
| Shift + Tab | Moves focus to the previous focusable element. | |
| Esc | Closes the popover and moves focus to the PopoverTrigger. |
The PopoverTrigger component does not render any DOM elements. It only passes through its children.
| Prop | Type | Default | Description |
|---|---|---|---|
| children * | ReactNode | PopoverTrigger needs at least two children: a <Button> and a <Popover>. | |
| isOpen | boolean | Whether the popover is open by default (controlled). | |
| defaultOpen | boolean | Whether the overlay is open by default (uncontrolled). |
| Name | Type | Description |
|---|---|---|
| onOpenChange | (isOpen: boolean) => void | Handler that is called when the overlay's open state changes. |
An overlay positioned relative to a trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
| side | 'center' | 'left' | 'right' | 'top' | 'bottom' | 'center' | Side of the screen the popover will open from. |
| offset | "number" | Spacing between the popover and the trigger across the main axis. | |
| crossOffset | "number" | Spacing between the popover and the trigger across the cross axis. | |
| children | ReactNode | (opts: PopoverRenderProps) => ReactNode | Children of the popover. A function may be provided to access a function to close the popover. | |
| className | string | (values: ButtonRenderProps) => string | The CSS className for the element. A function may be provided to compute the class based on component state. | |
| style | CSSProperties | The inline style for the element. |
| Name | Type | Description |
|---|---|---|
| id | string | The element's unique identifier. |
| aria-label | string | Defines a string value that labels the current element. |
| aria-labelledby | string | Identifies the element (or elements) that labels the current element. |
| aria-describedby | string | Identifies the element (or elements) that describes the object. |
| aria-details | string | Identifies the element (or elements) that provide a detailed, extended description for the object. |
The <PopoverTitle> has the same props as an <H2> and is mandatory so assistive technology announces the popover correctly.
If you want to visually hide the title, wrap it with <VisuallyHidden>.
<PopoverTrigger> <Button variant="ghost" className="border text-muted-400"> <Icon name="avatar" /> <VisuallyHidden>Account</VisuallyHidden> </Button> <Popover> {({ close }) => ( <> <VisuallyHidden> <PopoverTitle>Account</PopoverTitle> </VisuallyHidden> <Flex orientation="vertical"> <Flex orientation="vertical" gap="4" className="w-full border-b border-muted-100 px-5 py-3"> <Flex gap="8" className="mb-3"> <Icon name="avatar" className="h-10 w-10 text-muted-300" /> <Flex orientation="vertical"> <Span weight="semibold" className="leading-snug"> John Doe </Span> <Span size="xs" className="leading-tight text-muted-400"> john@gmail.com </Span> </Flex> </Flex> <Button variant="ghost" className="flex w-full justify-start gap-2 font-normal text-muted-500" autoFocus onPress={close}> <Icon name="magnifying-glass" /> <Span>Search</Span> </Button> <Button variant="ghost" className="flex w-full justify-start gap-2 font-normal text-muted-500" onPress={close}> <Icon name="avatar" /> <Span>Profile</Span> </Button> <Button variant="ghost" className="flex w-full justify-start gap-2 font-normal text-muted-500" onPress={close}> <Icon name="dashboard" /> <Span>Feed</Span> </Button> <Button variant="ghost" className="flex w-full justify-start gap-2 font-normal text-muted-500" onPress={close}> <Icon name="bar-chart" /> <Span>Analytics</Span> </Button> </Flex> <Flex orientation="vertical" gap="4" className="w-full border-b border-muted-100 px-5 py-3"> <Button variant="ghost" className="flex w-full justify-start gap-2 font-normal text-muted-500" onPress={close}> <Icon name="gear" /> <Span>Settings</Span> </Button> <Button variant="ghost" className="flex w-full justify-start gap-2 font-normal text-muted-500" onPress={close}> <Icon name="question-mark" /> <Span>Support</Span> </Button> </Flex> <Flex orientation="vertical" gap="4" className="w-full px-5 py-3"> <Button variant="ghost" className="flex w-full justify-start gap-2 font-normal text-muted-500" onPress={close}> <Icon name="exit" /> <Span>Log out</Span> </Button> </Flex> </Flex> </> )} </Popover></PopoverTrigger>Here's the <Popover /> component in action.
/* ### Overlays ### */@layer components { /* Popover */ .popover { @apply min-w-[18rem] rounded-xl border bg-background; }
.popover-arrow { @apply fill-background stroke-muted-300 stroke-1; }}