# Popover

Open contextual content next to a trigger.

Feedback form popover

[Complete TSX file](/examples/popover/default.tsx)

```tsx
"use client";

import { Button } from "@/siteplane/components/button";
import { Field, FieldLabel } from "@/siteplane/components/field";
import { Form } from "@/siteplane/components/form";
import {
  Popover,
  PopoverDescription,
  PopoverPopup,
  PopoverTitle,
  PopoverTrigger,
} from "@/siteplane/components/popover";
import { Textarea } from "@/siteplane/components/textarea";
import { useState } from "react";

export default function Example() {
  const [open, setOpen] = useState(false);
  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger render={<Button variant="outline" />}>
        Give feedback
      </PopoverTrigger>
      <PopoverPopup className="w-80">
        <PopoverTitle>Send feedback</PopoverTitle>
        <PopoverDescription>
          Tell us what would make this page more useful.
        </PopoverDescription>
        <Form
          className="mt-4 grid gap-4"
          onSubmit={(event) => {
            event.preventDefault();
            setOpen(false);
          }}
        >
          <Field>
            <FieldLabel>Feedback</FieldLabel>
            <Textarea
              name="feedback"
              placeholder="What could be better?"
              required
            />
          </Field>
          <Button type="submit">Send feedback</Button>
        </Form>
      </PopoverPopup>
    </Popover>
  );
}
```

## Installation

Complete [one-time setup](/docs/installation/) first.

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/popover
```

With npm: `npx shadcn@4.18.0 add @siteplane/popover`. [Registry JSON](/registry/popover.json) lists source files and dependencies.

For this page’s examples, also install:

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/button @siteplane/form @siteplane/input @siteplane/input-group @siteplane/textarea
```

Field is installed with Input.

## Usage

```tsx
import { Button } from "@/siteplane/components/button";
import {
  Popover,
  PopoverTrigger,
  PopoverPopup,
  PopoverTitle,
  PopoverDescription,
} from "@/siteplane/components/popover";

<Popover>
  <PopoverTrigger render={<Button variant="outline" />}>Status</PopoverTrigger>
  <PopoverPopup>
    <PopoverTitle>Project status</PopoverTitle>
    <PopoverDescription>On track for the October release.</PopoverDescription>
  </PopoverPopup>
</Popover>;
```

## Composition

```text
Popover
├── PopoverTrigger
└── PopoverPopup / PopoverContent
    ├── PopoverTitle
    ├── PopoverDescription
    └── PopoverClose
```

## Close button

Set `showCloseButton` on `PopoverPopup` for a close button in the top-end corner, the same one Dialog, Sheet and Drawer use. The first block of the content keeps clear of it. Use `PopoverClose` for any other close action, such as a Done button. Escape and clicks outside the popover also close it.

Notifications popover with a close button

[Complete TSX file](/examples/popover/close-button.tsx)

```tsx
"use client";

import { BellIcon } from "lucide-react";
import { Button } from "@/siteplane/components/button";
import {
  Popover,
  PopoverDescription,
  PopoverPopup,
  PopoverTitle,
  PopoverTrigger,
} from "@/siteplane/components/popover";

export default function Example() {
  return (
    <Popover>
      <PopoverTrigger
        render={
          <Button aria-label="Notifications" size="icon-md" variant="outline" />
        }
      >
        <BellIcon />
      </PopoverTrigger>
      <PopoverPopup className="w-72" showCloseButton>
        <PopoverTitle>Notifications</PopoverTitle>
        <PopoverDescription>
          You&apos;re all caught up. New mentions and assignments will appear
          here.
        </PopoverDescription>
      </PopoverPopup>
    </Popover>
  );
}
```

## Alignment

Use `align` to line the popover up with the start (default), center or end of its trigger. `side` sets the preferred side; the popover flips when there isn’t enough room.

Popover alignment

[Complete TSX file](/examples/popover/position.tsx)

```tsx
"use client";

import { Button } from "@/siteplane/components/button";
import {
  Popover,
  PopoverDescription,
  PopoverPopup,
  PopoverTitle,
  PopoverTrigger,
} from "@/siteplane/components/popover";

const alignments = [
  { align: "start", label: "Start" },
  { align: "center", label: "Center" },
  { align: "end", label: "End" },
] as const;

export default function Example() {
  return (
    <div className="flex flex-wrap gap-2">
      {alignments.map(({ align, label }) => (
        <Popover key={align}>
          <PopoverTrigger render={<Button variant="outline" />}>
            {label}
          </PopoverTrigger>
          <PopoverPopup align={align} className="w-56">
            <PopoverTitle>Project status</PopoverTitle>
            <PopoverDescription>
              On track: 12 of 18 tasks are done.
            </PopoverDescription>
          </PopoverPopup>
        </Popover>
      ))}
    </div>
  );
}
```

## Tooltip style

Set `tooltipStyle` when an info button only reveals a short hint. Unlike a tooltip, the popover also opens on click or tap; `openOnHover` on the trigger opens it on hover as well.

Password requirements hint

[Complete TSX file](/examples/popover/compact.tsx)

```tsx
"use client";

import { InfoIcon } from "lucide-react";
import { Button } from "@/siteplane/components/button";
import { Field, FieldLabel } from "@/siteplane/components/field";
import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput,
} from "@/siteplane/components/input-group";
import {
  Popover,
  PopoverPopup,
  PopoverTrigger,
} from "@/siteplane/components/popover";

export default function Example() {
  return (
    <Field className="w-full max-w-sm">
      <FieldLabel>Password</FieldLabel>
      <InputGroup>
        <InputGroupInput autoComplete="new-password" type="password" />
        <InputGroupAddon align="inline-end">
          <Popover>
            <PopoverTrigger
              openOnHover
              render={
                <Button
                  aria-label="Password requirements"
                  profile="field-action"
                  shape="square"
                />
              }
            >
              <InfoIcon />
            </PopoverTrigger>
            <PopoverPopup align="center" side="top" tooltipStyle>
              Use at least 8 characters.
            </PopoverPopup>
          </Popover>
        </InputGroupAddon>
      </InputGroup>
    </Field>
  );
}
```

## Glass

Set `variant="glass"` when the popover opens over a photo, a video or a color surface. The popup then shows a tinted, blurred view of what lies behind it; its padding and parts stay the same. [Glass](/docs/components/glass/) shows every component with a glass variant.

Glass popover

[Complete TSX file](/examples/popover/glass.tsx)

```tsx
"use client";

import { Button } from "@/siteplane/components/button";
import {
  Popover,
  PopoverDescription,
  PopoverPopup,
  PopoverTitle,
  PopoverTrigger,
} from "@/siteplane/components/popover";

export default function Example() {
  return (
    <Popover>
      <PopoverTrigger render={<Button variant="glass" />}>Share</PopoverTrigger>
      <PopoverPopup className="w-72" variant="glass">
        <PopoverTitle>Share link</PopoverTitle>
        <PopoverDescription>
          Anyone with the link can view this page.
        </PopoverDescription>
      </PopoverPopup>
    </Popover>
  );
}
```

## API reference

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| PopoverPopup.side | top \| right \| bottom \| left \| inline-start \| inline-end | bottom | Preferred side. |
| PopoverPopup.align | start \| center \| end | start | Alignment. |
| PopoverPopup.sideOffset | number | 4 | Gap from anchor. |
| PopoverPopup.alignOffset | number | 0 | Alignment offset. |
| PopoverPopup.variant | default \| glass | default | glass shows a tinted, blurred view of what lies behind the popup. |
| PopoverPopup.tooltipStyle | boolean | false | Small tooltip-like visual surface. |
| PopoverPopup.viewportPadding | compact \| default | default | Viewport padding profile. |
| PopoverPopup.anchor | Positioner anchor | trigger | Custom anchor. |
| PopoverPopup.showCloseButton | boolean | false | Renders a close icon action in the top-end corner; the first content block keeps clear of it. |
| PopoverPopup.closeProps | PopoverPrimitive.Close.Props | unset | Overrides the built-in close action, including aria-label (default: Close). |
| PopoverPopup.portalProps | PopoverPrimitive.Portal.Props | unset | Portal configuration. |
| PopoverTrigger.openOnHover | boolean | false | Also opens the popover on hover. |
| open / defaultOpen | boolean | false | Visibility. |
| onOpenChange | (open, eventDetails) => void | unset | Visibility callback. |
| onOpenChangeComplete | (open) => void | unset | After motion completes. |
Popover is the foundation Root. Trigger, Close, Title and Description wrap the
corresponding parts. Popup includes Portal, Positioner, Viewport and the
optional close button; PopoverContent aliases Popup. `PopoverCreateHandle`
creates a detached-trigger handle; `PopoverPrimitive` exports the namespace.
Styled parts accept string className. Popup focus and Root interaction options
follow [Base UI Popover](https://base-ui.com/react/components/popover); the
wrapper only forwards the listed positioner options, not arbitrary positioner
props.

[Read the installed source](/source/popover).

## Usage notes

Use Escape to dismiss and preserve focus restoration. Put fields and buttons in a popover rather than in a [Tooltip](/docs/components/tooltip/), whose content cannot be reached with the keyboard. The popup carries the Siteplane UI provider settings into its portal, so no additional provider is required.
