Anchored panel for mid-range tasks such as share sheets and short forms. Prefer Options Panel for denser inspectors, and Tooltip for hover-only hints.
Also known as: simple popover, light popover, lightweight popover, anchored popover, flyout
Install with the CLI, or copy the component source into your project.
Add popover (npm)
1npx --yes -p @default-file/ui df-ui add popover
Mid-range composition: header bar, link field, access toggle, switch, and footer actions.
Footer justify between places Previous and Next on opposite ends.
Surface styles for paper, muted, elevated, and inverse panels.
Density ladder for padding, type, radius, and max width.
Token-backed overrides for surface, radius, shadow, border, padding, and type.
Optional caret on each side with filter elevation.
animated defaults to true. Set false for an instant panel. prefers-reduced-motion disables motion.
badge is an open ReactNode slot. badgePosition below stacks under the title; end places it on the title row.
Parent state owns open. The panel always anchors to PopoverTrigger.
Distance from the trigger along the placement side.
start, center, and end on bottom and top. align auto picks the best fit; collision avoidance can flip the side.
Bottom
Top
Content-aware
Anchored panel for mid-range tasks such as share sheets and short forms. Compose header, body, and footer with kit controls. Prefer Options Panel for denser inspectors, and Tooltip for hover-only hints.
| Prop | Type | Default | Notes |
|---|---|---|---|
| open | boolean | - | Controlled open state. Placement still uses PopoverTrigger when something else sets open. |
| defaultOpen | boolean | false | Initial open state when open is not passed. The popover manages open after that. |
| onOpenChange | (open: boolean) => void | - | Called when open changes from the trigger, dismiss, PopoverClose, or parent updates. |
| children | ReactNode | - | Usually PopoverTrigger and PopoverContent. |
Placement anchor and usual toggle. The panel positions relative to this element when open.
| Prop | Type | Default | Notes |
|---|---|---|---|
| render | ReactElement | - | Host element for the trigger. Toggles open and marks the anchor. |
| children | ReactNode | - | Trigger content when not using render. |
| className | string | - | Additional styles on the trigger host. |
| Prop | Type | Default | Notes |
|---|---|---|---|
| variant | "default" | "muted" | "elevated" | "inverse" | "default" | Surface recipe. muted softens fill and caret elevation. elevated strengthens shadow. inverse flips against the nearest .dark theme. Chrome props override recipe tokens. |
| size | "sm" | "md" | "lg" | "md" | Density for padding, type, radius, and max width. Padding and radius props override the size recipe. |
| showArrow | boolean | false | Show a caret toward the trigger. The anchoring engine keeps the caret aimed at the trigger after collision clamping. Uses filter elevation so the shadow includes the caret silhouette. |
| animated | boolean | true | Open motion with opacity, scale, and short travel from the placement side. Set false for an instant panel. prefers-reduced-motion disables motion. |
| background | string | - | Panel fill. Prefer tokens such as var(--popover). Sets --df-popover-surface. |
| foreground | string | - | Panel text color. Prefer tokens such as var(--popover-foreground). Sets --df-popover-surface-fg. |
| borderColor | string | - | Border color. Prefer tokens such as var(--border). Sets --df-popover-border-color. |
| borderWidth | "none" | "hairline" | "thin" | "thick" | "hairline" | Border width step. Maps to --border-width-* via --df-popover-border-width. |
| shadow | string | - | Elevation override. Without showArrow, prefer box-shadow tokens and sets --df-popover-shadow. With showArrow, prefer filter tokens such as var(--df-shadow-popover) and sets --df-popover-elevation. |
| radius | "none" | "xxs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "full" | - | Corner radius step. Maps to --radius-* via --df-popover-radius. |
| cornerShape | "round" | "smooth" | - | Instance corner curve. Omit to inherit --df-corner-shape from the theme (set at create/init). |
| padding | string | - | Inset on all sides. Prefer spacing tokens. Sets each --df-popover-inset-*. |
| paddingX | string | - | Horizontal inset. Sets --df-popover-inset-left and --df-popover-inset-right. |
| paddingY | string | - | Vertical inset. Sets --df-popover-inset-top and --df-popover-inset-bottom. |
| paddingTop | string | - | Top inset. Sets --df-popover-inset-top. Wins over paddingY and padding. |
| paddingRight | string | - | Right inset. Sets --df-popover-inset-right. Wins over paddingX and padding. |
| paddingBottom | string | - | Bottom inset. Sets --df-popover-inset-bottom. With a direct PopoverFooter child, applied as footer bottom padding. |
| paddingLeft | string | - | Left inset. Sets --df-popover-inset-left. Wins over paddingX and padding. |
| gap | string | - | Gap between header, body, and footer. Prefer spacing tokens. Sets --df-popover-gap. |
| side | "top" | "bottom" | "left" | "right" | "bottom" | Preferred side. bottom and top are the usual bi-directional pair. left and right are supported. With collisionAvoidance, the panel can flip when space is tight. |
| align | "start" | "center" | "end" | "auto" | "center" | Alignment along the side. start, center, and end pin the panel. auto picks the best of those from available space. |
| sideOffset | number | 8 | Distance in pixels between the trigger and the panel along the placement side. |
| alignOffset | number | 0 | Shift in pixels along the alignment axis. Positive values move toward the end edge. |
| matchTriggerWidth | boolean | false | Lock the panel width to the trigger. Off by default so the panel sizes to content within the size max width. |
| portal | boolean | true | When true, render in document.body and copy the nearest .dark ancestor from the trigger. When false, render inline in the trigger tree. |
| dismissOnScroll | boolean | true | Close when the page or an ancestor scrolls. Set false for panels with drag or scrollable controls. |
| followScroll | boolean | true | Reposition while the page or an ancestor scrolls. Set false to keep the last placement until the next open. |
| collisionAvoidance | boolean | true | Flip and shift the panel to stay in view. Set false to keep the requested side and align. |
| className | string | - | Additional styles on the panel. |
| children | ReactNode | - | Panel content. Compose PopoverHeader, PopoverBody, and PopoverFooter as needed. |
Stacks the title row and description. Use PopoverHeaderBar when the title shares a row with close.
| Prop | Type | Default | Notes |
|---|---|---|---|
| gap | string | - | Space between the title row and description. Prefer spacing tokens. Sets --df-popover-header-gap. |
| children | ReactNode | - | Usually PopoverHeaderBar then PopoverDescription, or title and description alone. |
| className | string | - | Additional styles on the header. |
Title row with an end-aligned close or action on one midline.
| Prop | Type | Default | Notes |
|---|---|---|---|
| gap | string | - | Space between the title and trailing control. Prefer spacing tokens. Sets --df-popover-header-bar-gap. |
| children | ReactNode | - | PopoverTitle first, then PopoverClose (often a ghost icon-xs Button). |
| className | string | - | Additional styles on the title row. |
Panel title and accessible name. badge is an open ReactNode slot for status or meta.
| Prop | Type | Default | Notes |
|---|---|---|---|
| color | string | - | Title color. Prefer tokens. Sets --df-popover-title-color. |
| fontSize | string | - | Title size. Prefer type tokens. Sets --df-popover-title-size. |
| fontWeight | string | - | Title weight. Prefer tokens. Sets --df-popover-title-weight. |
| fontFamily | string | - | Title font family. Prefer theme font tokens. Sets --df-popover-title-font. |
| lineHeight | string | - | Title line height. Prefer tokens. Sets --df-popover-title-leading. |
| letterSpacing | string | - | Title letter spacing. Prefer tokens. Sets --df-popover-title-tracking. |
| badge | ReactNode | - | Open slot beside or under the title. Any ReactNode; Badge is common but not required. |
| badgePosition | "end" | "below" | "end" | end places the slot on the title row. below stacks it under the title. |
| children | ReactNode | - | Title text. Sets the accessible name on the panel. |
| className | string | - | Additional styles on the title. |
| Prop | Type | Default | Notes |
|---|---|---|---|
| color | string | - | Description color. Prefer tokens. Sets --df-popover-description-color. |
| fontSize | string | - | Description size. Prefer type tokens. Sets --df-popover-description-size. |
| fontWeight | string | - | Description weight. Prefer tokens. Sets --df-popover-description-weight. |
| fontFamily | string | - | Description font family. Prefer theme font tokens. Sets --df-popover-description-font. |
| lineHeight | string | - | Description line height. Prefer tokens. Sets --df-popover-description-leading. |
| letterSpacing | string | - | Description letter spacing. Prefer tokens. Sets --df-popover-description-tracking. |
| children | ReactNode | - | Supporting copy. Wired as aria-describedby when present. |
| className | string | - | Additional styles on the description. |
Main content region between header and footer.
| Prop | Type | Default | Notes |
|---|---|---|---|
| children | ReactNode | - | Kit controls such as Input, Toggle Group, and Switch. |
| className | string | - | Additional styles on the body. |
Action row. Default end-aligned. As a direct child of PopoverContent, receives the panel bottom inset by default. paddingTop and paddingBottom are independently overridable.
| Prop | Type | Default | Notes |
|---|---|---|---|
| justify | "end" | "between" | "start" | "end" | Action distribution along the footer. end for Cancel and primary. between for Previous and Next on opposite ends. start for a leading control. |
| paddingTop | string | - | Space above the actions. Prefer spacing tokens. Sets --df-popover-footer-padding-top. Default 0. |
| paddingBottom | string | - | Space below the actions. Prefer spacing tokens. Sets --df-popover-footer-padding-bottom. Default matches Content bottom inset when this footer is a direct child. |
| paddingX | string | - | Horizontal inset inside the footer. Prefer spacing tokens. Sets --df-popover-footer-padding-x. Default 0. |
| gap | string | calc(2 * var(--spacing-unit)) | Space between actions. Prefer spacing tokens. Sets --df-popover-footer-gap. |
| children | ReactNode | - | Usually Cancel via PopoverClose then a primary Button, or Previous and Next with justify between. |
| className | string | - | Additional styles on the footer. |
Dismisses the panel and returns focus to the trigger.
| Prop | Type | Default | Notes |
|---|---|---|---|
| render | ReactElement | - | Host element to merge onto, usually a Button. Prefer ghost icon-xs in PopoverHeaderBar. |
| children | ReactNode | - | Label or icon for the close control. |
| className | string | - | Additional styles on the close host. |
Behavior for portaled panels. Dismiss (Escape / outside click): Closes the panel and returns focus to the trigger when focus was inside. Role (disclosure): Non-modal anchored panel with no dialog role and no focus trap. The trigger exposes aria-expanded and aria-controls while open. Use PopoverTitle for an accessible name via aria-labelledby, or aria-label on PopoverContent. High contrast (forced-colors): Under forced-colors, the panel keeps a visible border and the trigger keeps a focus outline.
Theme defaults live on :root. Override these globally or on a local host.
| Token | Type | Default | Notes |
|---|---|---|---|
| --df-popover-width-sm | CSS length | 14rem | Max width for size sm. |
| --df-popover-width | CSS length | 18rem | Max width for size md. |
| --df-popover-width-lg | CSS length | 22rem | Max width for size lg. |
| --df-popover-width-safe | CSS length | min(var(--df-popover-width), calc(100vw - 8 * var(--spacing-unit))) | Viewport-clamped md width for consumers. |
| --df-popover-arrow-size | CSS length | calc(2 * var(--spacing-unit)) | Caret edge length. |
| --df-popover-arrow-offset | CSS length | var(--df-tooltip-arrow-offset) | Caret overlap on the panel edge. Shared with Tooltip. |
| --df-popover-arrow-align-nudge | CSS length | var(--df-tooltip-arrow-align-nudge) | Half-caret optical nudge for the trigger-tracked caret. Shared with Tooltip. |
| --df-anchor-arrow-cross | CSS length | 50% | Trigger-centered caret offset on the cross axis. Set by the anchoring engine after collision clamping. |
| --df-anchor-arrow-cross-inset | CSS length | calc(3 * var(--spacing-unit)) | Minimum inset that keeps the trigger-tracked caret on the panel edge. |
| --df-popover-surface | CSS color | var(--popover) | Panel fill. Set by background or variant. |
| --df-popover-surface-fg | CSS color | var(--popover-foreground) | Panel text. Set by foreground or variant. |
| --df-popover-border-color | CSS color | var(--border) | Border and caret edge color. Set by borderColor. |
| --df-popover-border-width | CSS length | var(--border-width-hairline) | Border width. Set by borderWidth. |
| --df-popover-shadow | CSS box-shadow | var(--df-shadow-md) | Box shadow when showArrow is false. Set by shadow or variant. |
| --df-popover-elevation | CSS filter | var(--df-shadow-popover) | Filter elevation when showArrow is true. Default var(--df-shadow-popover); muted uses var(--df-shadow-tooltip); elevated uses var(--df-shadow-popover-elevated). |
| --df-shadow-popover | CSS filter | drop-shadow(0 4px 6px rgb(0 0 0 / 0.1)) drop-shadow(0 2px 4px rgb(0 0 0 / 0.08)) | Default drop-shadow for caret popovers. |
| --df-shadow-popover-elevated | CSS filter | drop-shadow(0 12px 18px rgb(0 0 0 / 0.14)) drop-shadow(0 4px 8px rgb(0 0 0 / 0.1)) | Stronger drop-shadow for elevated caret popovers. |
| --df-popover-radius | CSS length | var(--radius-2xl) | Corner radius. Set by radius or size. |
| --df-popover-inset-top | CSS length | calc(3 * var(--spacing-unit)) | Shared top inset. Set by padding, paddingY, or paddingTop. |
| --df-popover-inset-right | CSS length | calc(4 * var(--spacing-unit)) | Shared right inset. Set by padding, paddingX, or paddingRight. |
| --df-popover-inset-bottom | CSS length | calc(3 * var(--spacing-unit)) | Shared bottom inset. Set by padding, paddingY, or paddingBottom. Applied to Content or Footer when a footer is present. |
| --df-popover-inset-left | CSS length | calc(4 * var(--spacing-unit)) | Shared left inset. Set by padding, paddingX, or paddingLeft. |
| --df-popover-padding-top | CSS length | var(--df-popover-inset-top) | Resolved top padding. Defaults to --df-popover-inset-top. |
| --df-popover-padding-right | CSS length | var(--df-popover-inset-right) | Resolved right padding. Defaults to --df-popover-inset-right. |
| --df-popover-padding-bottom | CSS length | var(--df-popover-inset-bottom) | Resolved bottom padding. Defaults to --df-popover-inset-bottom; 0 with a direct footer child. |
| --df-popover-padding-left | CSS length | var(--df-popover-inset-left) | Resolved left padding. Defaults to --df-popover-inset-left. |
| --df-popover-gap | CSS length | calc(3 * var(--spacing-unit)) | Gap between header, body, and footer. Set by gap. |
| --df-popover-header-gap | CSS length | calc(1.5 * var(--spacing-unit)) | Gap between title row and description. Set by PopoverHeader gap. |
| --df-popover-header-bar-gap | CSS length | calc(2 * var(--spacing-unit)) | Gap between title and close in PopoverHeaderBar. Set by PopoverHeaderBar gap. |
| --df-popover-footer-padding-top | CSS length | 0px | Footer top padding. Set by PopoverFooter paddingTop. |
| --df-popover-footer-padding-bottom | CSS length | 0px | Footer bottom padding. Defaults to --df-popover-inset-bottom with a direct footer child. |
| --df-popover-footer-padding-x | CSS length | 0px | Footer horizontal padding. Set by PopoverFooter paddingX. |
| --df-popover-footer-gap | CSS length | calc(2 * var(--spacing-unit)) | Gap between footer actions. Set by PopoverFooter gap. |
| --df-popover-title-color | CSS color | var(--df-popover-surface-fg) | Title color. Set by PopoverTitle color. |
| --df-popover-title-size | CSS length | inherit | Title font size. Set by PopoverTitle fontSize. |
| --df-popover-title-weight | CSS font-weight | var(--df-font-weight-semibold) | Title weight. Set by PopoverTitle fontWeight. |
| --df-popover-title-font | CSS font-family | inherit | Title font family. Set by PopoverTitle fontFamily. |
| --df-popover-title-leading | CSS line-height | var(--df-leading-5) | Title line height. Set by PopoverTitle lineHeight. |
| --df-popover-title-tracking | CSS letter-spacing | var(--df-tracking-snug) | Title letter spacing. Set by PopoverTitle letterSpacing. |
| --df-popover-description-color | CSS color | var(--muted-foreground) | Description color. Set by PopoverDescription color. |
| --df-popover-description-size | CSS length | var(--df-text-13) | Description font size. Set by PopoverDescription fontSize. |
| --df-popover-description-weight | CSS font-weight | var(--df-font-weight-normal) | Description weight. Set by PopoverDescription fontWeight. |
| --df-popover-description-font | CSS font-family | inherit | Description font family. Set by PopoverDescription fontFamily. |
| --df-popover-description-leading | CSS line-height | var(--df-leading-5) | Description line height. Set by PopoverDescription lineHeight. |
| --df-popover-description-tracking | CSS letter-spacing | normal | Description letter spacing. Set by PopoverDescription letterSpacing. |