Popover
A panel that opens against the control that asked for it, holds a few fields or a short list, and leaves the page behind it in use.
Try it
New appointment
Messages
- Elizabeth GrayElizabeth Gray16:40
Duis mollis, est non commodo luctus.
- Jonathan YoungJonathan Young15:39
Morbi leo risus, porta ac consectetur ac.
- Sandra BrownSandra Brown10:56
Vestibulum id ligula porta.
- Ashley BrooksAshley Brooks09:04
Bibendum pellentesque consectetur.
Two of the drawn panels, rebuilt from the system’s own parts, and a third with no header at all. Press Esc, or anywhere outside: the focus goes back to the button.
Choosing a popover
| When | Use |
|---|---|
| A few fields or a short list, about the control that opens it, and the page stays in use | Popover |
| It must be answered before anything else, or it is long | Dialog |
| A list of commands | Dropdown menu |
| Words about a control, with nothing to press | Tooltip |
A popover is not modal. The page behind it can be read, scrolled and pressed, and a press on it closes the panel, so nothing in a popover may be the only way to something, and nothing typed in it should be lost without a word: a form worth keeping is a dialog. The drawn User Menu is not this component: a list of commands is a dropdown menu, whatever stands above it.
Anatomy
| Part | Value |
|---|---|
| Radius | 12 |
| Elevation | lg, a level above a menu; a border in dark only |
| From the trigger | 4 |
| Header | 20 above, 24 inline, 16 to the divider |
| Title, Semibold | 18 / 24 |
| Body and footer | 24 of padding; buttons 12 apart, at the end |
| From the screen’s edge | 8 at least; the body scrolls |
The shell is the Dialog’s, smaller: a title, what it holds, and its buttons at the end. The four drawn panels are a product’s, and what they hold is the caller’s. The title is primary where the drawing has it secondary, as the Dialog’s is: it is the panel’s name.
One floating surface
The menu, the date picker, the page size of a pagination and this panel stand on one stylesheet: the overlay surface, a border in dark only where the shadow stops carrying the edge, the anchor, the flip when there is no room, and hiding when the trigger scrolls away. It was written out four times; it is written once, and each of the four keeps only its own padding, radius and width. A control that opens its own panel inside a popover, as the date picker above does, opens over it and does not close it.
Accessibility
The panel is a dialog that is not modal, named by its title or by aria-label; the trigger says it has one and whether it is open. It is the platform’s popover: Esc and a press outside close it, and the focus returns to the trigger, with no listener of the system’s own. On the way in the focus goes to the panel, or to initialFocus, the first field of a form. The panel follows its trigger in the document, so Tab goes from the button into it and out of it to what comes next. Where CSS anchor positioning is missing it opens in the middle of the screen and works the same.
Using it
import { Popover, Button } from 'alpenglow';
<Popover
trigger={(props) => <Button {...props}>New appointment</Button>}
title="New appointment"
width={424}
initialFocus={patient}
actions={({ close }) => (
<>
<Button variant="outline" tone="neutral" onClick={close}>Cancel</Button>
<Button onClick={() => { save(); close(); }}>Save</Button>
</>
)}
>
…the fields…
</Popover>| Prop | Type | Default |
|---|---|---|
trigger | (props: Popover | required |
children | React | required |
title | string | — |
aria-label | string, where there is no title | — |
headerActions | React | — |
actions | React | — |
placement | 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' | 'bottom-start' |
width | number | string | the content’s |
open | boolean | — |
onOpenChange | (open: boolean) => void | — |
initialFocus | Ref | the panel |
className | string | — |