Popover

An accessible popup anchored to a button.

PopoverExample

Examples

Without close button

Set closeButton={false} on PopoverHeader to hide the default close button.

PopoverNoCloseButtonExample

Custom positioning

Pass positionerProps to PopoverContent to customize the popup position.

PopoverWithPositionerPropsExample

Installation

Copy the source code below into your project:

tsx
import { Popover as BasePopover } from "@base-ui/react/popover";
import { cn } from "@/lib/utils";
import { XIcon } from "@phosphor-icons/react";

import { Button } from "./button";

const Popover = (props: BasePopover.Root.Props) => (
  <BasePopover.Root data-slot="popover" {...props} />
);

function PopoverTrigger(props: BasePopover.Trigger.Props) {
  return <BasePopover.Trigger data-slot="popover-trigger" {...props} />;
}

const PopoverPortal = (props: BasePopover.Portal.Props) => (
  <BasePopover.Portal data-slot="popover-portal" {...props} />
);
const PopoverClose = (props: BasePopover.Close.Props) => (
  <BasePopover.Close data-slot="popover-close" {...props} />
);

function PopoverContent({
  className,
  children,
  positionerProps,
  ...props
}: BasePopover.Popup.Props & {
  positionerProps?: BasePopover.Positioner.Props;
}) {
  return (
    <BasePopover.Portal>
      <BasePopover.Positioner
        {...positionerProps}
        collisionPadding={positionerProps?.collisionPadding || 8}
        sideOffset={positionerProps?.sideOffset || 8}
      >
        <BasePopover.Popup
          className={cn(
            "z-50 w-80 rounded-2xl bg-popover shadow-lg outline outline-border",
            "origin-(--transform-origin) transition-all duration-150",
            "data-starting-style:scale-90 data-starting-style:opacity-0",
            "data-ending-style:scale-90 data-ending-style:opacity-0",
            className,
          )}
          data-slot="popover-popup"
          {...props}
        >
          {children}
        </BasePopover.Popup>
      </BasePopover.Positioner>
    </BasePopover.Portal>
  );
}

function PopoverTitle({ className, ...props }: BasePopover.Title.Props) {
  return (
    <BasePopover.Title
      className={cn("text-lg font-bold text-foreground", className)}
      data-slot="popover-title"
      {...props}
    />
  );
}

function PopoverHeader({
  className,
  children,
  closeButton = true,
}: {
  className?: string;
  closeButton?: boolean;
  children?: React.ReactNode;
}) {
  return (
    <div className={cn("relative flex flex-col p-4", className)} data-slot="popover-header">
      {closeButton && (
        <PopoverClose
          className="absolute top-3 right-3"
          render={<Button className="size-5" size="icon" variant="secondary" />}
        >
          <XIcon className="size-3" />
        </PopoverClose>
      )}
      {children}
    </div>
  );
}

function PopoverBody({ className, children }: { className?: string; children?: React.ReactNode }) {
  return (
    <div className={cn("flex flex-col gap-3 px-4 pb-4", className)} data-slot="popover-body">
      {children}
    </div>
  );
}

export {
  Popover,
  PopoverTrigger,
  PopoverPortal,
  PopoverClose,
  PopoverContent,
  PopoverTitle,
  PopoverHeader,
  PopoverBody,
};

API Reference

Popover

This component does not add any props on top of Base UI Popover.Root. See the Base UI docs for the full API reference.

PopoverTrigger

This component does not add any props on top of Base UI Popover.Trigger. See the Base UI docs for the full API reference.

PopoverContent

The PopoverContent component extends the Base UI Popover.Popup props and adds the following:

PropTypeDefaultDescription
positionerPropsBasePopover.Positioner.Props-Props forwarded to the underlying Positioner component. Includes align, side, sideOffset, alignOffset, collisionPadding, etc.

PopoverHeader

PropTypeDefaultDescription
closeButtonbooleantrueWhether to show the default close button in the header.
classNamestring-Additional CSS classes to apply to the header container.

PopoverBody

PropTypeDefaultDescription
classNamestring-Additional CSS classes to apply to the body container.

PopoverTitle

This component does not add any props on top of Base UI Popover.Title. See the Base UI docs for the full API reference.

PopoverClose

This component does not add any props on top of Base UI Popover.Close. See the Base UI docs for the full API reference.

PopoverPortal

This component does not add any props on top of Base UI Popover.Portal. See the Base UI docs for the full API reference.