Docs
Popover

Popover

Displays rich content in a portal, triggered by a button.

Loading...

Installation

Copy and paste the following code into your project.

"use client";
 
import { cva } from "cva";
import type { PopoverRenderProps } from "react-aria-components";
import {
  Dialog,
  DialogTrigger,
  Heading,
  Popover as RaPopover,
} from "react-aria-components";
 
import { autoRef, cn, withRenderProps } from "@/lib/utils";
 
/* -------------------------------------------------------------------------- */
/*                                  Variants                                  */
/* -------------------------------------------------------------------------- */
 
export const popoverVariants = {
  root: cva({
    base: cn(
      "z-50 w-72 rounded-md border bg-popover text-popover-foreground shadow-md outline-none",
      "s-placement-top:slide-in-from-bottom-2",
      "s-placement-bottom:slide-in-from-top-2",
      "s-placement-left:slide-in-from-right-2",
      "s-placement-right:slide-in-from-left-2",
      "s-entering:animate-in s-entering:fade-in-0 s-entering:zoom-in-95",
      "s-exiting:animate-out s-exiting:fade-out-0 s-exiting:zoom-out-95",
    ),
  }),
  header: cva({
    base: "space-y-2 px-4 pt-4",
  }),
  title: cva({
    base: "font-medium leading-none",
  }),
  description: cva({
    base: "text-sm text-muted-foreground",
  }),
  content: cva({
    base: "p-4",
  }),
};
 
/* -------------------------------------------------------------------------- */
/*                                 Components                                 */
/* -------------------------------------------------------------------------- */
 
/* --------------------------------- Trigger -------------------------------- */
 
export const PopoverTrigger = DialogTrigger;
 
/* ---------------------------------- Root ---------------------------------- */
 
export type PopoverProps = Omit<
  React.ComponentPropsWithRef<typeof RaPopover>,
  "children"
> & {
  children?:
    | React.ReactNode
    | ((values: PopoverRenderProps & { close: () => void }) => React.ReactNode);
};
 
export const Popover = autoRef(
  ({ className, children, ...props }: PopoverProps) => {
    return (
      <RaPopover className={cn(popoverVariants.root(), className)} {...props}>
        {(popoverValues) => (
          <Dialog className="focus-within:outline-none">
            {({ close }) => (
              <>{withRenderProps(children)({ ...popoverValues, close })}</>
            )}
          </Dialog>
        )}
      </RaPopover>
    );
  },
);
 
/* --------------------------------- Header --------------------------------- */
 
export type PopoverHeaderProps = React.ComponentPropsWithRef<"div">;
 
export const PopoverHeader = autoRef(
  ({ className, ...props }: PopoverHeaderProps) => {
    return (
      <div className={cn(popoverVariants.header(), className)} {...props} />
    );
  },
);
 
/* ---------------------------------- Title --------------------------------- */
 
export type PopoverTitleProps = React.ComponentPropsWithRef<typeof Heading>;
 
export const PopoverTitle = autoRef(
  ({ className, ...props }: PopoverTitleProps) => {
    return (
      <Heading
        slot="title"
        className={cn(popoverVariants.title(), className)}
        {...props}
      />
    );
  },
);
 
/* ------------------------------- Description ------------------------------ */
 
export type PopoverDescriptionProps = React.ComponentPropsWithRef<"p">;
 
export const PopoverDescription = autoRef(
  ({ className, ...props }: PopoverDescriptionProps) => {
    return (
      <p className={cn(popoverVariants.description(), className)} {...props} />
    );
  },
);
 
/* --------------------------------- Content -------------------------------- */
 
export type PopoverContentProps = React.ComponentPropsWithRef<"div">;
 
export const PopoverContent = autoRef(
  ({ className, ...props }: PopoverContentProps) => {
    return (
      <div className={cn(popoverVariants.content(), className)} {...props} />
    );
  },
);

Update the import paths to match your project setup.