On this page
Import
import { Popover } from '@envsemble/envui';
Usage
A Popover opens from its trigger, such as a Button or an IconButton, which must take a ref and props: it receives the press handler, aria-haspopup and aria-expanded. title is a heading at the top that names it; without one, name it with aria-label. children is its content.
import { Button, Popover, Column, Text } from '@envsemble/envui';
import { IconInfo } from '@envsemble/envui/icons/Info';
export default function DocumentDetails() {
return (
<Column gap={4} align="start">
<Popover
// Shown open in the docs; without defaultOpen, it opens from its trigger.
defaultOpen
title="Launch plan.md"
trigger={
<Button variant="secondary" startIcon={<IconInfo />}>
Details
</Button>
}
>
<Text emphasis="muted">Changed today by Alex Morgan. 3 open decisions, 1 blocked.</Text>
<Text emphasis="muted">Shared with everyone at Northwind.</Text>
</Popover>
</Column>
);
}A small form
A function child receives close, for an action inside that closes the popover once it is done, such as a form's submit.
<Popover aria-label="Rename document" width="lg" trigger={<Button>Rename</Button>}>
{(close) => (
<form onSubmit={(event) => rename(event, close)}>
<TextField label="Name" name="name" required />
<Button variant="secondary" onClick={close}>
Cancel
</Button>
<Button type="submit">Rename</Button>
</form>
)}
</Popover>
Controlled
Leave it uncontrolled, with defaultOpen to start open, or control it with open and onOpenChange, which receives the requested state and why: the trigger, Esc, a press outside, focus leaving it, or close as close-press.
<Popover
title="Assignees"
open={open}
onOpenChange={(next) => {
setOpen(next);
if (next) setDraft(applied); // Each time it opens, start from the filters in use.
}}
trigger={<Button startIcon={<IconFilterList />}>Assignees</Button>}
>
{people.map((person) => (
<Checkbox
key={person}
label={person}
checked={draft.includes(person)}
onCheckedChange={(checked) => toggle(person, checked)}
/>
))}
<Button
onClick={() => {
setApplied(draft);
setOpen(false);
}}
>
Apply
</Button>
</Popover>
Width, side and alignment
width sets how wide the popover grows with its content: md, the default, from 12 rem up to 20 rem, or lg, from 20 rem up to 28 rem; it narrows to fit the window. side is bottom, the default, top, left, right, or inline-start and inline-end, which follow the text direction; it flips to the other side without room. align is start, center, the default, or end.
<Popover
title="Billing periods"
side="right"
align="start"
trigger={<IconButton variant="text" icon={<IconHelp />} aria-label="About billing periods" />}
>
<Text>Members added later are billed from the next period.</Text>
</Popover>
Customize
Every popup, a popover, a menu, a Select's or a Combobox's list, a picker, a hover card, rich text suggestions and the command palette, is frosted. Three properties, set on a .env-theme boundary, change them all:
--env-popup-opacity, 88 % in light and 90 % in dark, how much of the popup's color covers what is behind it;100%makes popups solid. The color is--env-color-bg-popup.--env-popup-blur, 1.375 rem, the blur of what shows through, with a little more saturation.--env-popup-shadow, a soft shadow in the text's color in light and a deeper shade of the page in dark: with the avatars', envUI's only shadow.
In dark a faint hairline of the text color keeps a frosted popup's edge, where its shadow barely shows. At high contrast, with reduced transparency and under forced colors popups are solid, with their elevation edge and no blur or shadow; at high contrast the edge is a modal's, --env-elevation-3-border, the strongest. Tooltips are frosted too, at --env-tooltip-opacity with a smaller --env-tooltip-shadow, as Tooltip describes.
className, style, ref and data attributes reach the surface, env-popover, which has data-width="lg" when large and renders on PopupSurface in the trigger's text direction and theme. Its title is env-popover-title.
Accessibility
You provide
- A
titleor anaria-label, and a name for an icon-only trigger. - The actions inside, and a call to
closewhen one is done.
envUI provides
aria-haspopup="dialog"andaria-expandedon the trigger, and adialognamed by its title.- Focus moved in on open, and back to the trigger when Esc or
closecloses it. - The theme of its trigger in the portal.
Props
Popover
A floating panel beside its trigger, for details or a small form: it opens on press, moves focus into itself, and closes with Esc, a press outside or when focus leaves it. className, style, ref and data attributes go to the popover's surface.
| Prop | Type | Description |
|---|---|---|
triggerrequired | ReactElement | The control that opens and closes the popover, such as a Button or an IconButton. It must take a ref and props: it receives the press handler, aria-haspopup and aria-expanded. |
title | ReactNode | A heading at the top, such as the name of what the popover describes; it names the popover. |
childrenrequired | ReactNode( | The popover's content, or a function that receives close, for an action inside it that should close the popover once it is done, such as a form's submit. |
aria-label | string | The popover's accessible name when it has no title, such as Rename document. |
sideDefault 'bottom' | 'top''bottom''left''right''inline-start''inline-end' | The side of the trigger the popover opens on: top, bottom, left, right, or inline-start and inline-end, which follow the text direction. It flips to the other side without room. |
alignDefault 'center' | 'start''center''end' | How the popover lines up with the trigger along that side: its start, center or end. |
open | boolean | Whether a controlled popover is open; update it from onOpenChange. |
defaultOpenDefault false | boolean | Whether an uncontrolled popover starts open. |
onOpenChange | ( | Receives the requested state, and why, each time the popover asks to open or close: from the trigger, Esc, a press outside, focus leaving it or close (`close-press`). |
widthDefault 'md' | 'md''lg' | The widest the popover grows: md, 20 rem, for details and a field or two; lg, 28 rem, for a longer form. It is as wide as its content from 12 rem up, and narrows to fit the window. |
skeletonDefault false | boolean | Shows it and its content as a busy skeleton while that loads; turning it on or off renders the content anew. |
Also accepts the native props of <div>, such as ref, className and aria-* attributes.
Part names
Each part's class and state attributes are public and versioned, for an application's CSS to style.
env-popover- The popover.
env-popover-title- The popover's title.
data-widthlg
Changelog
- 1.0.0
widthismdorlg, the widest the popover grows as it sizes to its content;sidetakesinline-startandinline-end;className,style,refand data attributes reach the surface, which renders on PopupSurface in the trigger's text direction.Popovers take the level-2 elevation edge, with no shadow.
- 1.0.0-prerelease.6
A popover opens over
--env-motion-duration-medium, fading in and growing from 98 % with--env-motion-ease-enter, rather than growing from 96 % over the slow duration, so it shows from its first frames rather than late.A popover's corners are the popups' own, concentric with their rows and half a row's height, 20 px and 16 px at the compact scale, rather than a surface's 28 px and 22 px; dialogs and sheets keep a surface's.
- 1.0.0-prerelease.5
Popovers are frosted: the popup's color lets a little of what is behind through, blurred, with a soft shadow and no outline edge but a faint hairline in dark, and is solid with its edge at high contrast and with reduced transparency:
--env-popup-opacity,--env-popup-blurand--env-popup-shadow. Its inset is a panel's, as wide as a popup row's corner: 14 px, 11.2 px at the compact scale.