Default
Show the codeHide the code
Default, code
<PopoverTrigger>
<Button variant="outline">Billing contact</Button>
<Popover {...args} />
</PopoverTrigger>A small non-modal panel anchored to a button, for extra detail or a quick edit. Esc closes it and focus returns.
These are the real React components. Use them with a mouse, touch or keyboard, and switch the theme and density for every example at once.
Default, code
<PopoverTrigger>
<Button variant="outline">Billing contact</Button>
<Popover {...args} />
</PopoverTrigger>Open, code
<PopoverTrigger defaultOpen>
<Button variant="outline">Billing contact</Button>
<Popover {...args} showArrow />
</PopoverTrigger>With a field, code
const RenameExample = ({ open }: { open?: boolean }) => (
<PopoverTrigger defaultOpen={open}>
<Button variant="outline">Rename</Button>
<Popover title="Rename project">
<div className="flex flex-col gap-stack-sm">
<TextField label="Project name" defaultValue="Northwind" />
<Button slot="close">Save</Button>
</div>
</Popover>
</PopoverTrigger>
);
<RenameExample />With a field, open, code
const RenameExample = ({ open }: { open?: boolean }) => (
<PopoverTrigger defaultOpen={open}>
<Button variant="outline">Rename</Button>
<Popover title="Rename project">
<div className="flex flex-col gap-stack-sm">
<TextField label="Project name" defaultValue="Northwind" />
<Button slot="close">Save</Button>
</div>
</Popover>
</PopoverTrigger>
);
<RenameExample open />From an icon button, code
<PopoverTrigger>
<IconButton icon={Info} label="About seats" variant="outline" showTooltip={false} />
<Popover aria-label="About seats" placement="end">Each seat is one person who can sign in. Team plans start at two seats.</Popover>
</PopoverTrigger>Coach mark (arrow), code
<div className="flex min-h-72 items-center justify-center">
<PopoverTrigger defaultOpen>
<Button variant="outline">Filters</Button>
<Popover {...args} showArrow />
</PopoverTrigger>
</div>The 15 design tokens Popover reads, with the value each has in the theme and density chosen above. Change a token and the component follows, in Figma and in code.
| Token | Value now | CSS variable |
|---|---|---|
| color.text.default | … | --sd-color-text-default |
| color.text.disabled | … | --sd-color-text-disabled |
| elevation.2 | … | --sd-elevation-2 |
| layer.dropdown | … | --sd-layer-dropdown |
| listbox.bg | … | --sd-listbox-bg |
| listbox.border | … | --sd-listbox-border |
| listbox.option-fg | … | --sd-listbox-option-fg |
| listbox.option-height | … | --sd-listbox-option-height |
| listbox.option-hover | … | --sd-listbox-option-hover |
| listbox.radius | … | --sd-listbox-radius |
| radius.sm | … | --sd-radius-sm |
| spacing.gap.sm | … | --sd-spacing-gap-sm |
| spacing.inset.lg | … | --sd-spacing-inset-lg |
| spacing.inset.md | … | --sd-spacing-inset-md |
| spacing.stack.sm | … | --sd-spacing-stack-sm |
The npm package isn’t published yet. When it is, this is the install line; until then, this page runs the same build of the package (from commit fa3abf8).
Install
npm i @superduperui/react @superduperui/tokensImport
import { Popover, PopoverTrigger, popoverSurface, popoverItem } from "@superduperui/react"Popover also takes the props of the React Aria component it’s built on.
| Prop | Type | What it does |
|---|---|---|
title | string | Optional visible heading. Without one, give the popover an `aria-label`. |
children | ReactNode | Panel content: text, links, fields. Optional when the title says it all. |
placement | 'top' | 'bottom' | 'start' | 'end'Default 'bottom' | Side of the trigger the panel opens on (it flips when there is no room). Default bottom. |
showArrow | booleanDefault false | Draw a small arrow pointing at the trigger, from whichever side the panel opens on (coach marks). Default false. |
aria-label | string | Accessible name when there is no title. |
Screen readers announce "Billing contact, button" then on open "Billing contact, dialog".
WCAG 2.2 AAA criteria the component meets in Comfortable density: 1.4.6, 1.4.9, 2.1.3, 2.3.2, 2.4.13, 2.5.5, 2.5.6, 2.3.3.
Compact density meets AA (2.5.8, 24px targets), not AAA.
| axe-core (WCAG A, AA, AAA and best practice) | 140 runs across every story, theme, density and width: 0 violations |
|---|---|
| Rendered text contrast | 135 text runs: 0 below 7:1, lowest 11.42:1 |
| Target size | 16 targets: 0 under 44px in Comfortable |
| Focus appearance (2.4.13) | 18 focus stops in 3 browser engines: all pass |
| Keyboard script | Chromium 5 of 5, Firefox 5 of 5, WebKit 5 of 5 |
Manual passes with VoiceOver and NVDA haven’t been done yet.
Each step is scripted and run in Chromium, Firefox and WebKit.
| Key | What happens |
|---|---|
| Tab | Tab reaches the trigger |
| Enter | Enter opens the panel and focus moves into it |
| Tab | Tab moves to the field inside the panel |
| Escape | Esc closes the panel and focus returns to the trigger |
| Enter | Enter on the trigger opens it again |
The Figma component is Popover, with Placement (Bottom, Top, Start, End); Width (Default, Wide). The Figma library isn’t published yet.
Figma to code: Placement → placement (Bottom = "bottom", Top = "top", Start = "start", End = "end"); Title → title when Show title; Show arrow → showArrow; Content → children; Width (Default, Wide; preview only).