Default actions
Use Popper when the layer needs low-level positioning control.
<Popper>
<PopperTrigger>
<Button variant="outline">Open actions</Button>
</PopperTrigger>
<PopperContent>
<Button size="sm">Approve request</Button>
</PopperContent>
</Popper>Placement grid
Popper accepts every Popper v2 placement string, including side and alignment combinations.
<Popper placement="top-start" arrow>
<PopperTrigger>
<Button variant="outline">top-start</Button>
</PopperTrigger>
<PopperContent size="sm">Placement: top-start</PopperContent>
</Popper>Arrow, offset, and trigger width
Use arrow, offset, and matchReferenceWidth together for rich select-like panels.
<Popper arrow offset={[0, 14]} matchReferenceWidth>
<PopperTrigger>
<Button className="w-72" variant="outline">Open match-width panel</Button>
</PopperTrigger>
<PopperContent>
<Input placeholder="Search workflows" />
</PopperContent>
</Popper>Custom modifier
Custom modifiers run inside the Popper lifecycle. Use them for advanced styling hooks, measurement, or boundary behavior.
const modifiers = [
{
name: 'addDataAttribute',
enabled: true,
phase: 'write',
fn({ state }) {
state.elements.popper.setAttribute('data-workflow-layer', 'employee-search');
},
},
];
<Popper modifiers={modifiers} placement="right-start" arrow>
...
</Popper>Virtual reference
Use referenceElement for context menus and canvas-style interactions where the anchor is a point rather than an element.
Right-click inside this area. The panel follows a virtual element at the pointer coordinates.
const virtualReference = {
getBoundingClientRect: () => ({
width: 0,
height: 0,
x,
y,
top: y,
right: x,
bottom: y,
left: x,
} as DOMRect),
};
<Popper referenceElement={virtualReference} strategy="fixed" open={open} onOpenChange={setOpen}>
<PopperContent>Context actions</PopperContent>
</Popper>