Skip to content
GetUrUI

Popover

.md

Click-to-open panel anchored to its trigger that scales from the trigger edge with a spring and flips above or below to stay in the viewport.

popoveroverlaydropdowndialogfloatingcollisionformanchor

Installation

$npx shadcn@latest add @geturui/popover
Download source (.zip)

Usage

usage.tsx
1import { Popover } from "@/components/ui/popover";
2
3export function InviteButton() {
4  return (
5    <Popover label="Invite to project" trigger={<button>Invite</button>}>
6      {({ close }) => (
7        <form onSubmit={(e) => { e.preventDefault(); close(); }} className="grid gap-2">
8          <input type="email" placeholder="[email protected]" aria-label="Email" />
9          <button type="submit">Send invite</button>
10        </form>
11      )}
12    </Popover>
13  );
14}

Props

PropTypeDefaultDescription
trigger*ReactElement—Focusable element that toggles the panel. Receives onClick, aria-expanded and aria-controls.
children*ReactNode | ((api: { close: () => void }) => ReactNode)—Panel content; the render-function form gets a close() helper.
openboolean—Controlled open state.
defaultOpenbooleanfalseOpen on mount when uncontrolled.
onOpenChange(open: boolean) => void—Called when the panel opens or closes.
side"top" | "bottom""bottom"Preferred side; flips when the other side has more room.
align"start" | "center" | "end""center"Horizontal alignment to the trigger; shifted to stay 8px inside the viewport.
sideOffsetnumber8Gap between trigger and panel in px.
labelstring—Accessible name for the dialog when it has no labelled heading.
classNamestring—Classes for the panel surface.

Accessibility

  • Trigger gets aria-haspopup="dialog", aria-expanded and aria-controls; the panel is role="dialog".
  • Focus moves to the first field when it opens. Escape closes and returns focus to the trigger; outside press or tabbing away closes without moving focus.
  • With reduced motion the panel fades without scaling or blur.

Related