An anchored frosted panel for arbitrary content: a short form, a set of options, a details block.
Popover opens a panel against its trigger, in the same frosted glass as Select and Menu. The trigger is any button you pass; Popover adds aria-expanded, aria-controls and the click handler. It flips above when there is no room below and follows scroll and resize.
Focus moves to the first focusable element inside (or the panel) but is not trapped. Esc closes it and returns focus to the trigger; a press outside closes it too. Open state is uncontrolled by default, or controlled with open and onOpenChange.
inline renders the open panel in the page flow: no portal, scrim, focus trap, scroll lock or outside-click listener. It exists for docs, previews and static mock-ups; never ship it as the live overlay.
Installation
npx shadcn@latest add KezLahd/rime/popoverAlso installs: base.
Usage
import { Button, Popover } from "@/components/ui";
<Popover label="Canvas dimensions" trigger={<Button variant="secondary">Dimensions</Button>}>
…fields…
</Popover>Examples
Open
From its trigger
API
Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.
Popover
| Prop | Type | Default | Description |
|---|---|---|---|
| triggerRequired | ReactElement<TriggerProps> | The button that opens it. Gets aria-expanded, aria-controls and the click handler. | |
| childrenRequired | ReactNode | The panel's content: a short form, a set of filters, a details block. | |
| label | string | The panel's accessible name ("Edit dimensions"). Use it when the content has no heading. | |
| open | boolean | Controlled open state. Leave unset for uncontrolled. | |
| defaultOpen | boolean | ||
| onOpenChange | (open: boolean) => void | ||
| side | FloatSide | "bottom" | Preferred side; flips when there is no room. |
| align | FloatAlign | "start" | |
| width | number | Panel width in px. Defaults to the content's width (min 220px). | |
| inline | boolean | Render the open panel in the page flow under the trigger: not portalled, no outside-click or Esc handling. For docs, previews and static mock-ups. | |
| className | string |
Theme tokens
Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.
| Token | Default | Live value |
|---|---|---|
| --popover-content-pad | calc(16px * var(--density)) | … |
| --popover-max-width | 380px | … |
| --popover-min-width | 220px | … |
| --popover-radius | var(--r-lg) | … |
System tokens it reads
| Token | Default | Live value |
|---|---|---|
| --border-w | tokens.css | … |
| --density | tokens.css | … |
| --dur | tokens.css | … |
| --dur-slow | tokens.css | … |
| --ease-out | tokens.css | … |
| --focus-ring | tokens.css | … |
| --ink-body | tokens.css | … |
| --popover-blur | tokens.css | … |
| --popover-border | tokens.css | … |
| --popover-shadow | tokens.css | … |
| --popover-surface | tokens.css | … |
| --r-lg | tokens.css | … |
| --text-small | tokens.css | … |
| --z-popover | tokens.css | … |
Accessibility
- The panel is role="dialog" named by label (or by a heading you give it); the trigger carries aria-expanded and aria-controls.
- Focus moves into the panel on open and back to the trigger on Esc. It is non-modal: Tab can leave it.
- Do not put the only route to an action in a popover that opens on hover; Popover opens on press only.
Do and don't
Do
- Keep it to one small task: a few fields, a choice, a summary.
- Give it a label when the content has no heading.
Don't
- Don't use it for a list of actions; that is Menu.
- Don't put a long form in it; use Sheet or Modal.
For AI agents
This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.
Open popover.mdRelated: hover-card, menu, tooltip