Popover
Use popover with the current published Askr packages.
@askrjs/ui/popover0.0.13@askrjs/themes/popover0.0.13
How to use popover
Popover should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.
- Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
- Keep popover labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
- Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { Button, Popover, PopoverContent, PopoverTrigger } from '@askrjs/themes/components';
<Popover>
<PopoverTrigger asChild><Button variant="outline">Filters</Button></PopoverTrigger>
<PopoverContent><ProjectFilters /></PopoverContent>
</Popover>Purpose
Popover is a non-modal floating panel anchored to a trigger element — think a filter panel, a color picker, or a small settings menu that appears next to what you clicked. Unlike Dialog it doesn't block the rest of the page or trap focus behind a backdrop; it just opens near its trigger and closes on outside interaction or Escape.
Install and import
Import behavior from `@askrjs/ui/popover` and the themed version from `@askrjs/themes/popover`. The root package re-exports the same set — `Popover`, `PopoverTrigger`, `PopoverContent`, `PopoverClose` — so use whichever import path fits your bundling setup.
Live examples
`Popover` wraps a `PopoverTrigger` and a `PopoverPortal` containing `PopoverContent`; put a `PopoverClose` inside the content if you want an explicit dismiss button rather than relying on outside-click. Pass `side` and `align` on `PopoverContent` to control which edge of the trigger it opens from and how it lines up against it.
Anatomy
The tree is `Popover` > `PopoverTrigger` and `PopoverPortal` > `PopoverContent`, with `PopoverClose` optionally nested inside the content. There's no separate overlay component — popovers don't dim the background, since they're meant to be lightweight and non-blocking compared to Dialog.
State model
Open state works exactly like Dialog's — `open`, `defaultOpen`, `onOpenChange` on the root — but there's no `modal` prop, because a popover never blocks the rest of the page by design. Positioning state (which side it actually rendered on, once it's flipped to avoid the viewport edge) is tracked internally and exposed through `data-side`/`data-align` attributes rather than anything you manage yourself.
Keyboard and accessibility
`PopoverContent` renders with `role="dialog"` and is labelled from the trigger by default, with `aria-labelledby`/`aria-label` as your override if the trigger's own text isn't descriptive enough. Focus is trapped inside the content while open and restored to the trigger on close, and it sits behind a dismissable layer so outside clicks and Escape close it the way users expect from any transient overlay.
Styling and tokens
`PopoverContent` accepts `side`, `align`, `sideOffset`, and a `width` of `sm`/`md`/`lg`, all of which show up as `data-side`/`data-align` attributes the default theme keys its positioning CSS off of. It sits at `--ak-z-popover` in the shared z-index scale, above dropdowns but below modals and tooltips.
API
`PopoverContent` layers `forceMount`, `side`, `align`, `sideOffset`, and `width` on top of standard div props. `PopoverTrigger` and `PopoverClose` are the usual button-like components with `onPress`/`disabled`. `PopoverPortal` just wraps `children` — it doesn't have positioning props of its own, since that all lives on `PopoverContent`.
Edge cases
If the popover is anchored near a viewport edge, the positioning logic will flip `side` automatically to keep it visible — don't hardcode layout assumptions based on the `side` prop you passed in, read the resolved `data-side` attribute if you need to react to where it actually landed. Popovers containing form inputs need care around outside-click dismissal — a click that starts inside the content and ends outside (e.g. a native `<select>` dropdown) can register as an outside interaction if you're not careful with `onInteractOutside`.
Related pages
Hover Card is a close cousin for content that should appear on hover rather than click. If you need to block the rest of the page and trap focus for something more significant than a small panel, use Dialog instead.