Popover

A small floating panel that opens from a button, for extra detail or a few quick controls.

import { Button } from "@hel/ui/button"
import {
  Popover,

When to use it

Use a popover for a little extra content that people open on purpose: an explanation, a few settings, a short form, a share link. It stays open until people click outside it, press Escape, or close it, and they can interact with what is inside.

If the content is only a short name or hint that shows on hover, use a Tooltip. For a list of actions, use a Dropdown Menu. When the content needs the person's full attention, or blocks the page until they answer, use a Dialog.

Import

import {
  Popover,
  PopoverTrigger,
  PopoverContent,
  PopoverHeader,
  PopoverTitle,
  PopoverDescription,
  PopoverClose,
} from "@hel/ui/popover"

Anatomy

Popover holds the open state, PopoverTrigger is the button that opens it, and PopoverContent is the panel.

Inside the panel, PopoverHeader groups a PopoverTitle and a PopoverDescription, and puts a close button at the end of the row. Set showClose={false} when the popover is short enough that people do not need it. The title and the description are linked to the panel for screen readers.

Pass your own button to the trigger with render, so the two are one element, as the examples do.

<Popover>
  <PopoverTrigger render={<Button variant="outline">Payment terms</Button>} />
  <PopoverContent className="w-72">
    <PopoverHeader>
      <PopoverTitle>Net 30</PopoverTitle>
      <PopoverDescription>The customer pays within 30 days.</PopoverDescription>
    </PopoverHeader>
  </PopoverContent>
</Popover>

Examples

With a form

A popover can hold controls. Put a Field for each one, and use PopoverClose with render to make the save button close the panel when it is pressed. Do the saving in its onClick.

import { Settings } from "lucide-react"

import { Button } from "@hel/ui/button"

Position

side sets which side of the trigger the panel opens on, and it flips to the other side when there is no room. The default is bottom. align lines it up with the start, center or end of the trigger, and sideOffset is the gap. Use inline-start and inline-end when the layout can be right to left.

import { Button } from "@hel/ui/button"
import { Flex } from "@hel/ui/flex"
import {

Width and spacing

The panel is as wide as its content. Set a width with className, such as w-72, so the text wraps in a comfortable line length. padding takes a step of the spacing scale, and defaults to xl.

Controlling it

The popover opens and closes by itself. To open it from your own code, or to know when it is open, use open and onOpenChange on Popover. defaultOpen starts it open. disableAnimation on the content turns the open and close motion off.

Props

PopoverContent

PropTypeDefault
side"top" | "bottom" | "left" | "right" | "inline-start" | "inline-end""bottom"
align"start" | "center" | "end""center"
sideOffsetnumbernone
paddinga spacing step"xl"
disableAnimationbooleanfalse

PopoverHeader

PropTypeDefault
showClosebooleantrue

Popover

Takes every prop of the Base UI popover, such as open, defaultOpen and onOpenChange.