Popover
Displays content in a portal relative to the triggering button element.

Installation
npx shadcn@latest add @tetra-ui/popoverUsage
First ensure that you have the PortalHost component in your root layout.
import { PortalHost } from "@/components/ui/portal";
export default function RootLayout() {
return (
<>
<Stack />
<PortalHost />
</>
);
}import { Button, ButtonText } from "@/components/ui/button";
import {
Popover,
PopoverContent,
PopoverOverlay,
PopoverPortal,
PopoverTrigger,
} from "@/components/ui/popover";<Popover>
<PopoverTrigger asChild>
<Button>
<ButtonText>Open</ButtonText>
</Button>
</PopoverTrigger>
<PopoverPortal>
<PopoverOverlay />
<PopoverContent>
<Text>Popover Content</Text>
</PopoverContent>
</PopoverPortal>
</Popover>Positioning
Control placement with side and align on PopoverContent:
<PopoverContent side="top" align="center">
<Text>Tooltip above the trigger</Text>
</PopoverContent>Supported values:
side:"top"|"bottom"|"left"|"right"align:"start"|"center"|"end"
Use sideOffset and alignOffset to fine-tune distance from the trigger. Set width="trigger" to match the trigger width, or pass a percentage or pixel value.
Without overlay
Omit PopoverOverlay for lightweight tooltips that don't dim the background:
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Open</Button>
</PopoverTrigger>
<PopoverPortal>
<PopoverContent>
<Text>No backdrop</Text>
<PopoverClose asChild>
<Button size="sm" variant="link">Close</Button>
</PopoverClose>
</PopoverContent>
</PopoverPortal>
</Popover>Controlled
Pass open and onOpenChange for controlled state:
const [open, setOpen] = useState(false);
<Popover open={open} onOpenChange={setOpen}>
{/* ... */}
</Popover>Scrollable content
Wrap long content in a ScrollView and constrain the popover height:
<PopoverContent className="h-1/2 p-0" width="50%">
<ScrollView className="p-4">
{/* long content */}
</ScrollView>
</PopoverContent>