---
title: Popover
description: An accessible popup anchored to a button.
links:
  doc: https://base-ui.com/react/components/popover
  anatomy: https://base-ui.com/react/components/popover#anatomy
  api: https://base-ui.com/react/components/popover#api-reference
---

```tsx
import { Button } from "@/components/ui/button";
import { Field } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
import {
  Popover,
  PopoverDescription,
  PopoverPopup,
  PopoverTitle,
  PopoverTrigger,
} from "@/components/ui/popover";
import { Textarea } from "@/components/ui/textarea";

export function PopoverDemo() {
  return (
    <Popover>
      <PopoverTrigger render={<Button variant="outline" />}>Open Popover</PopoverTrigger>
      <PopoverPopup className="w-xs">
        <PopoverTitle>Send us feedback</PopoverTitle>
        <PopoverDescription>Let us know how we can improve.</PopoverDescription>
        <Form className="mt-4">
          <Field>
            <Textarea aria-label="Send feedback" id="feedback" placeholder="How can we improve?" />
          </Field>
          <Button type="submit">Send feedback</Button>
        </Form>
      </PopoverPopup>
    </Popover>
  );
}
```

## Installation

<ComponentSource name="popover" title="components/ui/popover.tsx" />

## Usage

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

```tsx
<Popover>
  <PopoverTrigger render={<Button variant="outline" />}>Open popover</PopoverTrigger>
  <PopoverPopup>
    <PopoverTitle>Title</PopoverTitle>
    <PopoverDescription>Description goes here.</PopoverDescription>
  </PopoverPopup>
</Popover>
```

## Examples

### Align

Change the alignment by setting the `positionerProps` align property to `start`, `center`, or `end`.

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

export function PopoverDemo() {
  return (
    <div className="flex items-center gap-5">
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Start</PopoverTrigger>
        <PopoverPopup positionerProps={{ align: "start" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Center</PopoverTrigger>
        <PopoverPopup positionerProps={{ align: "center" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>End</PopoverTrigger>
        <PopoverPopup positionerProps={{ align: "end" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
    </div>
  );
}
```

### Side

Change the side by setting the `positionerProps` side property to `top`, `right`, `bottom`, `left`, `inline-start` or `inline-end`.

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

export function PopoverDemo() {
  return (
    <div className="grid grid-cols-3 items-center gap-5">
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Top</PopoverTrigger>
        <PopoverPopup positionerProps={{ side: "top" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Bottom</PopoverTrigger>
        <PopoverPopup positionerProps={{ side: "bottom" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Left</PopoverTrigger>
        <PopoverPopup positionerProps={{ side: "left" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Right</PopoverTrigger>
        <PopoverPopup positionerProps={{ side: "right" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Inline start</PopoverTrigger>
        <PopoverPopup positionerProps={{ side: "inline-start" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
      <Popover>
        <PopoverTrigger render={<Button variant="outline" />}>Inline end</PopoverTrigger>
        <PopoverPopup positionerProps={{ side: "inline-end" }}>
          <PopoverTitle>Title</PopoverTitle>
          <PopoverDescription>Description goes here.</PopoverDescription>
        </PopoverPopup>
      </Popover>
    </div>
  );
}
```

### With close button

```tsx
import { IconBell, IconX } from "@tabler/icons-react";

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

export function PopoverDemo() {
  return (
    <Popover>
      <PopoverTrigger render={<Button variant="outline" size="icon" />}>
        <IconBell />
      </PopoverTrigger>
      <PopoverPopup className="w-full max-w-xs">
        <PopoverClose
          aria-label="Close"
          className="absolute end-2 top-2"
          render={<Button size="icon-sm" variant="ghost" />}
        >
          <IconX />
        </PopoverClose>
        <div>
          <PopoverTitle>Notifications</PopoverTitle>
          <PopoverDescription>You are all caught up. Good job!</PopoverDescription>
        </div>
        <PopoverClose render={<Button variant="outline" className="mt-5" />}>Close</PopoverClose>
      </PopoverPopup>
    </Popover>
  );
}
```

### With arrow

To add an arrow pointing to the trigger, set `showArrow` to `true` on the `PopoverPopup`.

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

export function PopoverDemo() {
  return (
    <Popover>
      <PopoverTrigger render={<Button variant="outline" />}>Open Popover</PopoverTrigger>
      <PopoverPopup showArrow positionerProps={{ className: "max-w-xs w-full", side: "top" }}>
        <PopoverTitle>Title</PopoverTitle>
        <PopoverDescription>Description goes here.</PopoverDescription>
      </PopoverPopup>
    </Popover>
  );
}
```

### Tooltip style

Pass `tooltipStyle` to the `PopoverPopup` to make the popover look like a tooltip. Pass `openOnHover` to the `PopoverTrigger` to open the popover on hover instead of click.

```tsx
"use client";

import { IconInfoCircle } from "@tabler/icons-react";

import { Button } from "@/components/ui/button";
import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group";
import { Popover, PopoverPopup, PopoverTrigger } from "@/components/ui/popover";

export default function Particle() {
  return (
    <InputGroup className="max-w-xs">
      <InputGroupInput aria-label="Password" placeholder="Password" type="password" />
      <InputGroupAddon align="inline-end">
        <Popover>
          <PopoverTrigger
            openOnHover
            render={<Button aria-label="Password requirements" size="icon-xs" variant="ghost" />}
          >
            <IconInfoCircle />
          </PopoverTrigger>
          <PopoverPopup tooltipStyle positionerProps={{ side: "top" }}>
            <p>Min. 8 characters</p>
          </PopoverPopup>
        </Popover>
      </InputGroupAddon>
    </InputGroup>
  );
}
```

### Animated

You can create animated popovers that smoothly transition between different triggers using detached triggers. This pattern allows multiple triggers to share a single popover popup, with automatic animations for position, size, and content changes.

To create detached triggers:

1. Create a handle using `popoverCreateHandle`
2. Attach the same handle to multiple `PopoverTrigger` components
3. Each trigger provides a `payload` prop containing the content component
4. Use a single `Popover` component with the handle to render the popup

```tsx
"use client";

import { IconBell, IconList, IconUserCircle } from "@tabler/icons-react";

import { cn } from "@/lib/cn";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button, buttonVariants } from "@/components/ui/button";
import {
  Popover,
  PopoverDescription,
  PopoverPopup,
  PopoverTitle,
  PopoverTrigger,
  PopoverViewport,
  popoverCreateHandle,
} from "@/components/ui/popover";

const popoverHandler = popoverCreateHandle<React.ComponentType>();

export function PopoverDemo() {
  return (
    <div className="flex items-center gap-3">
      <PopoverTrigger
        handle={popoverHandler}
        payload={NotificationsContent}
        render={<Button variant="outline" size="icon" />}
      >
        <IconBell />
      </PopoverTrigger>
      <PopoverTrigger
        handle={popoverHandler}
        payload={ActivityContent}
        render={<Button variant="outline" size="icon" />}
      >
        <IconList />
      </PopoverTrigger>
      <PopoverTrigger
        handle={popoverHandler}
        payload={ProfileContent}
        render={<Button variant="outline" size="icon" />}
      >
        <IconUserCircle />
      </PopoverTrigger>

      <Popover handle={popoverHandler}>
        {({ payload: Payload }) => (
          <PopoverPopup showArrow className="p-0">
            <PopoverViewport>{Payload !== undefined && <Payload />}</PopoverViewport>
          </PopoverPopup>
        )}
      </Popover>
    </div>
  );
}

function NotificationsContent() {
  return (
    <>
      <PopoverTitle>Notifications</PopoverTitle>
      <PopoverDescription>You are all caught up. Good job!</PopoverDescription>
    </>
  );
}

function ActivityContent() {
  return (
    <>
      <PopoverTitle>Activity</PopoverTitle>
      <PopoverDescription>Nothing interesting happened recently.</PopoverDescription>
    </>
  );
}

function ProfileContent() {
  return (
    <div>
      <div className="grid grid-cols-[auto_auto] gap-x-4">
        <Avatar className="size-12">
          <AvatarImage src="https://github.com/zbmzubayer.png" alt="Zbm Zubayer" />
          <AvatarFallback>ZM</AvatarFallback>
        </Avatar>
        <div>
          <PopoverTitle>ZBM Zubayer</PopoverTitle>
          <span className="text-muted-foreground text-sm">Pro plan</span>
        </div>
      </div>
      <div className="mt-2 flex flex-col gap-2 border-muted border-t pt-2 text-sm">
        <a href="#" className={cn(buttonVariants({ variant: "secondary" }))}>
          Profile settings
        </a>
        <Button variant="danger-soft">Log out</Button>
      </div>
    </div>
  );
}
```
