Examples
Informational popover
A titled popup gives more context without creating a modal task.
Informational Popover with title, description, arrow, and close
"use client";
import { Button } from "@phuctech/ui/components/button";
import { Popover, PopoverArrow, PopoverClose, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "@phuctech/ui/components/popover";
export function Example() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline">Workspace status</Button>} />
<PopoverContent>
<PopoverArrow />
<PopoverTitle>Workspace status</PopoverTitle>
<PopoverDescription>All services are operational and the last sync finished a few seconds ago.</PopoverDescription>
<PopoverClose render={<Button size="sm" variant="ghost">Close</Button>} />
</PopoverContent>
</Popover>
);
}
Positions and arrow
Side, alignment, spacing, and an optional arrow keep the popup anchored.
Popover with configurable placement
import { Button } from "@phuctech/ui/components/button";
import { Popover, PopoverArrow, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "@phuctech/ui/components/popover";
export function Example() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline">Open positioned popover</Button>} />
<PopoverContent side="bottom" align="center" sideOffset={10}>
<PopoverArrow />
<PopoverTitle>Positioned content</PopoverTitle>
<PopoverDescription>The popup can flip when the viewport has less room.</PopoverDescription>
</PopoverContent>
</Popover>
);
}Small form
Interactive content belongs in a popover when it is brief and related to its trigger.
Popover containing a small form
"use client";
import { Button } from "@phuctech/ui/components/button";
import { Field, FieldLabel } from "@phuctech/ui/components/field";
import { Input } from "@phuctech/ui/components/input";
import { Popover, PopoverClose, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "@phuctech/ui/components/popover";
export function Example() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline">Edit label</Button>} />
<PopoverContent>
<PopoverTitle>Edit label</PopoverTitle>
<PopoverDescription>Make one short change without leaving the current task.</PopoverDescription>
<Field>
<FieldLabel htmlFor="popover-label">Label</FieldLabel>
<Input id="popover-label" defaultValue="Project directory" />
</Field>
<div className="flex justify-end gap-2">
<PopoverClose render={<Button size="sm" variant="outline">Cancel</Button>} />
<PopoverClose render={<Button size="sm">Save</Button>} />
</div>
</PopoverContent>
</Popover>
);
}
Long content
A bounded popup scrolls its growing content instead of clipping it.
Popover with bounded long content
"use client";
import { Button } from "@phuctech/ui/components/button";
import { Popover, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "@phuctech/ui/components/popover";
const notes = ["Keep the title specific.", "Connect descriptions to their task.", "Preserve focus when closing.", "Allow the growing region to scroll.", "Keep actions near the content."];
export function Example() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline">Open review notes</Button>} />
<PopoverContent className="max-h-48">
<PopoverTitle>Review notes</PopoverTitle>
<PopoverDescription>Long content scrolls inside the popup boundary.</PopoverDescription>
<div className="grid gap-2 text-sm">{notes.concat(notes, notes).map((note, index) => <p key={`${note}-${index}`} className="rounded-md border border-border p-2">{note}</p>)}</div>
</PopoverContent>
</Popover>
);
}
Popover inside Dialog
Nested layers keep their focus and portal boundaries explicit.
Popover nested in a Dialog
"use client";
import { Button } from "@phuctech/ui/components/button";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@phuctech/ui/components/dialog";
import { Popover, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "@phuctech/ui/components/popover";
export function Example() {
return (
<Dialog>
<DialogTrigger render={<Button>Open settings</Button>} />
<DialogContent>
<DialogHeader><DialogTitle>Settings</DialogTitle><DialogDescription>Popover content remains a small, related layer.</DialogDescription></DialogHeader>
<Popover>
<PopoverTrigger render={<Button variant="outline">More details</Button>} />
<PopoverContent>
<PopoverTitle>About this setting</PopoverTitle>
<PopoverDescription>Use a popover for a brief explanation inside a focused dialog task.</PopoverDescription>
</PopoverContent>
</Popover>
</DialogContent>
</Dialog>
);
}
When to use
Use Popover for a small amount of related content anchored to a trigger. Use Tooltip for passive, brief context and Dialog when the task must take focus or needs confirmation.
Usage
"use client";
import { Button } from "@phuctech/ui/components/button";
import { Popover, PopoverArrow, PopoverClose, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "@phuctech/ui/components/popover";
export function Example() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline">Workspace status</Button>} />
<PopoverContent>
<PopoverArrow />
<PopoverTitle>Workspace status</PopoverTitle>
<PopoverDescription>All services are operational and the last sync finished a few seconds ago.</PopoverDescription>
<PopoverClose render={<Button size="sm" variant="ghost">Close</Button>} />
</PopoverContent>
</Popover>
);
}
Give the popup a title when it contains a task, and use PopoverDescription for supporting context. Keep the growing region bounded so long content scrolls inside the popup.
Behavior
- Click or keyboard activation opens the anchored popup; outside press and Escape close it.
- Focus returns to the trigger after closing unless the feature supplies an intentional final focus target.
side,align, and offset props are preferences; Base UI can flip placement near a viewport edge.
API
Tokens
Accessibility
- Keep the trigger keyboard reachable and give the popup a title when it is interactive.
- Verify Escape, outside press, focus return, and nested Dialog behavior.
- Do not hide a required instruction or error only inside a Popover.