Popover
Things that open next to the button that opened them, without blocking the page: menus, pickers, extra detail. Built on the native popover attribute, so a click outside or Escape closes it.
Other components
Examples
A menu of actions
The trigger is the <Action> that opens it. Pressing an item closes the menu, and so do a click outside and Escape.
function Menu() {
const share = () => {};
const edit = () => {};
const remove = () => {};
return (
<Popover
intent="popover.menu"
label="Article actions"
trigger={<Action intent="action.reveal" label="More actions" icon={<Ellipsis aria-hidden className="size-4" />} />}
>
<Action intent="action.share" onClick={share}>Share</Action>
<Action intent="action.edit" onClick={edit}>Edit</Action>
<Action intent="action.delete" onClick={remove}>Delete</Action>
</Popover>
);
}Picking one
options as data, value and onChange. Picking closes it, and selectionSummary writes the trigger text.
function Picker() {
const [order, setOrder] = useState('newest');
return (
<Popover
intent="popover.picker"
label="Sort order"
trigger={<Action intent="choice.open">{selectionSummary(ORDERS, order, 'Sort by')}</Action>}
options={ORDERS}
value={order}
onChange={(next) => setOrder(next as string)}
/>
);
}Picking several
popover.picker.many stays open while you pick. The intent decides one or many, never a prop.
function PickMany() {
const [sources, setSources] = useState<string[]>(['Wired']);
return (
<Popover
intent="popover.picker.many"
label="Sources"
trigger={<Action intent="choice.open">{selectionSummary(SOURCES, sources, 'All sources')}</Action>}
options={SOURCES}
value={sources}
onChange={(next) => setSources(next as string[])}
/>
);
}Detail on demand
popover.info holds a few words about something, opened only when asked for.
<Layout intent="layout.group" className="flex-row items-center">
<Text intent="text.label">Daily digest</Text>
<Popover intent="popover.info" label="About the daily digest" trigger={<Action intent="action.reveal">What is this?</Action>}>
<Text intent="text.body">One email each morning with the articles your sources published since the last one.</Text>
</Popover>
</Layout>Intents it renders
One domain, with its own page of neighbours and examples. The intent decides the element; these are the starter intents.
Popover popover.*
4 intentspopover.menuA short list of commands or links that opens from a button: more actions, an account menu. Closes when one is pressed
<div popover>popover.pickerChoices that open from a button, one of which is picked: a sort order, a category. Picking one closes it
<div popover>popover.picker.manyChoices that open from a button, any number of which can be picked: sources, tags. Stays open while picking
<div popover>popover.infoMore detail about something, opened on demand: what a setting does, where a number comes from
<div popover>
Props
Plus its element’s usual attributes (id, onClick, aria-*, data-*). No className or style.
intentrequiredpopover.menu,popover.pickerorpopover.info.PopoverIntenttriggerrequiredThe
<Action>that opens it. Popover connects the two and places itself next to it.ReactElementlabelrequiredThe accessible name: what it holds, like "Article actions".
stringchildrenThe content:
<Action>s for a menu, choices for a picker, text for detail.ReactNodeoptionsA picker’s choices as data, for lists from a database or a CMS. They render as a listbox (
role="option",aria-selected), announced like a native select.{ value, label?, disabled? }[]valueA picker’s choice: one value, or several when its intent picks many (
popover.picker.many).string | string[]onChangeCalled with the new choice, or with every picked value when its intent picks many.
(value) => voidkeepOpenStay open when something inside is pressed. Pickers that pick many stay open anyway.
booleanunsafeClassNameBypasses the intent. Needs a
// prongs-unsafe: <reason>comment on the line above, andprongs checkcounts it.string
Rules
The trigger is an
<Action>with a button, never a link. A picker’s trigger ischoice.open, withselectionSummary(options, value, placeholder)as its text.Whether a picker picks one or many comes from its intent, never a prop.
The arrow keys, Home, End and first letters move between items; Escape or a press closes it and focus goes back to the trigger.
Inside a menu, actions look like menu items whatever their intent; the menu decides.
Anything that needs the user’s full attention is a
<Dialog>, not a popover.