Getting Started
Components
- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
A popover that explains a term.
"use client"
import { Button } from "@workspace/ui/components/button"
import {
Popover,
PopoverContent,
PopoverDescription,
PopoverHeader,
PopoverTitle,
PopoverTrigger,
} from "@workspace/ui/components/popover"
export function PopoverDemo() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline" />}>What is ApoB?</PopoverTrigger>
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Apolipoprotein B</PopoverTitle>
<PopoverDescription>
Counts the particles that carry cholesterol into artery walls. It
predicts heart risk better than LDL-C alone.
</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>
)
}
Usage
Use a popover for extra detail or a small control that the reader opens on purpose: a definition, a date picker, a short filter. For a one-line label on hover, use a Tooltip. For a task that blocks the page, use a Dialog.
Import it from @workspace/ui/components/popover.
Anatomy
- Popover — Holds the open state.
- PopoverTrigger — Opens the popover on click.
- PopoverContent — The floating panel. Sets placement.
- PopoverHeader — Stacks the title and description.
- PopoverTitle — The panel heading.
- PopoverDescription — Muted body text.
Notes
- The popover flips to the other side when there is no room.
- Escape and a click outside close it.
- Pass a button through
renderon the trigger to reuse the Button styles.
Examples
Placement
Use side to pick which side of the trigger it opens on.
"use client"
import { Button } from "@workspace/ui/components/button"
import {
Popover,
PopoverContent,
PopoverDescription,
PopoverHeader,
PopoverTitle,
PopoverTrigger,
} from "@workspace/ui/components/popover"
const sides = ["top", "right", "bottom", "left"] as const
export function PopoverPlacement() {
return (
<div className="flex flex-wrap items-center justify-center gap-3">
{sides.map((side) => (
<Popover key={side}>
<PopoverTrigger render={<Button variant="ghost" className="capitalize" />}>
{side}
</PopoverTrigger>
<PopoverContent side={side} className="w-56">
<PopoverHeader>
<PopoverTitle className="capitalize">{side}</PopoverTitle>
<PopoverDescription>Opens on the {side} of its trigger.</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>
))}
</div>
)
}
Alignment
align lines the popover up with the start, center, or end of its trigger.
"use client"
import { Button } from "@workspace/ui/components/button"
import {
Popover,
PopoverContent,
PopoverDescription,
PopoverHeader,
PopoverTitle,
PopoverTrigger,
} from "@workspace/ui/components/popover"
const aligns = ["start", "center", "end"] as const
export function PopoverAlign() {
return (
<div className="flex flex-wrap items-center justify-center gap-3">
{aligns.map((align) => (
<Popover key={align}>
<PopoverTrigger render={<Button variant="outline" className="capitalize" />}>
{align}
</PopoverTrigger>
<PopoverContent align={align} className="w-56">
<PopoverHeader>
<PopoverTitle className="capitalize">{align}</PopoverTitle>
<PopoverDescription>Lines up with the {align} of its trigger.</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>
))}
</div>
)
}
With form
A popover can hold a small form, such as setting a target value.
"use client"
import { Button } from "@workspace/ui/components/button"
import {
NumberField,
NumberFieldDecrement,
NumberFieldGroup,
NumberFieldIncrement,
NumberFieldInput,
} from "@workspace/ui/components/number-field"
import {
Popover,
PopoverContent,
PopoverDescription,
PopoverHeader,
PopoverTitle,
PopoverTrigger,
} from "@workspace/ui/components/popover"
export function PopoverForm() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline" />}>Set target</PopoverTrigger>
<PopoverContent className="w-72">
<PopoverHeader>
<PopoverTitle>Daily step target</PopoverTitle>
<PopoverDescription>Shown as a line on your activity chart.</PopoverDescription>
</PopoverHeader>
<div className="flex items-center gap-2">
<NumberField size="sm" defaultValue={8000} min={0} step={500}>
<NumberFieldGroup>
<NumberFieldDecrement />
<NumberFieldInput aria-label="Daily step target" />
<NumberFieldIncrement />
</NumberFieldGroup>
</NumberField>
<Button size="sm">Save</Button>
</div>
</PopoverContent>
</Popover>
)
}
Props
These are the props you set most often. Unlisted props pass through to the underlying element.
Popover
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | false | Open on first render. |
open | boolean | — | Open state when controlled. |
onOpenChange | (open) => void | — | Called when the popover opens or closes. |
PopoverContent
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top", "right", "bottom", "left", "inline-start", or "inline-end" | bottom | Side of the trigger to open on. |
align | "start", "center", or "end" | center | Alignment along that side. |
sideOffset | number | 4 | Gap from the trigger in pixels. |
alignOffset | number | 0 | Shift along the side in pixels. |
className | string | — | Classes merged onto the panel. |