Rime

Popover

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/popover

Also installs: base.

Usage

import { Button, Popover } from "@/components/ui";

<Popover label="Canvas dimensions" trigger={<Button variant="secondary">Dimensions</Button>}>
  …fields…
</Popover>

Examples

Open

The panel under its trigger, drawn inline.

From its trigger

Press the button. Esc or a press outside closes it.

API

Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.

Popover

Popover props
PropTypeDefaultDescription
triggerRequiredReactElement<TriggerProps>The button that opens it. Gets aria-expanded, aria-controls and the click handler.
childrenRequiredReactNodeThe panel's content: a short form, a set of filters, a details block.
labelstringThe panel's accessible name ("Edit dimensions"). Use it when the content has no heading.
openbooleanControlled open state. Leave unset for uncontrolled.
defaultOpenboolean
onOpenChange(open: boolean) => void
sideFloatSide"bottom"Preferred side; flips when there is no room.
alignFloatAlign"start"
widthnumberPanel width in px. Defaults to the content's width (min 220px).
inlinebooleanRender 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.
classNamestring

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.

Popover per-component tokens
TokenDefaultLive value
--popover-content-padcalc(16px * var(--density))…
--popover-max-width380px…
--popover-min-width220px…
--popover-radiusvar(--r-lg)…

System tokens it reads

Popover system tokens
TokenDefaultLive value
--border-wtokens.css…
--densitytokens.css…
--durtokens.css…
--dur-slowtokens.css…
--ease-outtokens.css…
--focus-ringtokens.css…
--ink-bodytokens.css…
--popover-blurtokens.css…
--popover-bordertokens.css…
--popover-shadowtokens.css…
--popover-surfacetokens.css…
--r-lgtokens.css…
--text-smalltokens.css…
--z-popovertokens.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.md

Related: hover-card, menu, tooltip