Popover
A small panel that opens from a button and stays out of the way.
SourcePackage @weft-js/warpPlayground
Preview
tsx
import { Popover } from '@weft-js/warp'export function Basic() { return ( <Popover label="What is a preview?" title="Preview deploys" description="Every branch gets its own address, so you can try a change before it goes live." /> )}Installation
npm install @weft-js/warpUsage
tsx
import { Popover } from '@weft-js/warp'<Popover label="What is a preview?" title="Preview deploys" description="Every branch gets its own address, so you can try a change before it goes live." />Placement
Use side to pick where it opens. With no room there, it flips.
tsx
import { Popover } from '@weft-js/warp'export function Sides() { return ( <> <Popover label="Top" side="top" title="Top" description="Opens above the button." /> <Popover label="Bottom" side="bottom" title="Bottom" description="Opens below the button." /> <Popover label="Left" side="left" title="Left" description="Opens before the button." /> <Popover label="Right" side="right" title="Right" description="Opens after the button." /> </> )}Alignment
Use align to line it up with the button.
tsx
import { Popover } from '@weft-js/warp'export function Aligns() { return ( <> <Popover label="Start" align="start" title="Start" description="Lines up with the left edge. The default." /> <Popover label="Center" align="center" title="Center" description="Sits in the middle." /> <Popover label="End" align="end" title="End" description="Lines up with the right edge." /> </> )}Trigger styles
trigger takes any Button prop.
tsx
import { Popover } from '@weft-js/warp'export function Trigger() { return ( <> <Popover label="Soft" trigger={{ emphasis: 'soft' }} title="Soft" /> <Popover label="With an icon" trigger={{ icon: 'info', emphasis: 'ghost', tone: 'neutral' }} title="Ghost" /> <Popover label="Small" trigger={{ size: 'sm' }} title="Small" /> </> )}Closing from inside
Anything with data-close-popover closes it.
tsx
import { state } from '@weft-js/core'import { Button, Popover, Row, Stack, Text } from '@weft-js/warp'export function Close() { const on = state('Nobody is on call') return ( <Stack gap="related" align="center"> <Text subtle>{on.value}</Text> <Popover label="Take the pager" title="Go on call?" description="Alerts for every project will come to you tonight."> <Row gap="related" justify="end"> <Button size="sm" emphasis="ghost" tone="neutral" data-close-popover="">Not now</Button> <Button size="sm" data-close-popover="" onClick={() => (on.value = 'You are on call')}>Go on call</Button> </Row> </Popover> </Stack> )}A filter
A popover opens a small panel from its trigger, here a set of filter chips.
tsx
import { state } from '@weft-js/core'import { Chip, Popover, Row, Text } from '@weft-js/warp'export function Filter() { const on = state(['Failed']) const flip = (s: string) => (on.value = on.value.includes(s) ? on.value.filter(x => x !== s) : [...on.value, s]) return ( <Row gap="related"> <Popover label={`Status (${on.value.length})`} trigger={{ icon: 'filter' }} title="Show deploys that are"> <Row gap="tight"> {STATUSES.map(s => <Chip key={s} pressed={on.value.includes(s)} onClick={() => flip(s)}>{s}</Chip>)} </Row> </Popover> <Text subtle>{on.value.join(', ') || 'Everything'}</Text> </Row> )}type Status = 'Live' | 'Building' | 'Failed' | 'Paused'const STATUSES = ['Live', 'Building', 'Failed']When to use
Playground
Side
Align
import { Popover } from '@weft-js/warp'<Popover label="Details" title="storefront" description="Deployed 2 minutes ago by Priya." />Accessibility
- Enter
- Opens it and moves focus inside
- Esc
- Closes and returns focus to the button
- Tab
- Leaving the panel closes it
- It is a non-modal dialog, named by its title, else by its button.
- The button reports whether it is open.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
label | unknown | — | The button's text. |
title | unknown | — | A heading in the panel. Also names it. |
description | unknown | — | A line under the title. |
side | Side | — | Which side of the button it opens on. |
align | Align | — | How it lines up with the button. |
trigger | ButtonProps | — | Button props for the trigger. |
inline | boolean | false | Draws the panel open under its trigger, in the page's flow: no top layer or light dismiss. The trigger still shows and hides it. For docs and previews. |
children | unknown | — | What it contains. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="popover"] [data-part="content"]
contenttitledescription