VisorVisor
ComponentsOverlay

Popover

A floating panel that appears next to a trigger element. Built on Radix UI with configurable alignment, offset, and controlled state support.

Basic Popover

Alignment Variants

Use the align prop on PopoverContent to align the panel relative to the trigger.

Side Positioning

Use the side prop to control which side of the trigger the panel opens on.

With Form Content

Popovers are commonly used to contain small forms or settings panels.

Controlled State

Use open and onOpenChange to fully control when the popover is shown.

import { useState } from 'react';
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover/popover';
import { Button } from '@/components/ui/button/button';

export default function ControlledPopover() {
  const [open, setOpen] = useState(false);

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button variant="outline">{open ? 'Close' : 'Open'}</Button>
      </PopoverTrigger>
      <PopoverContent>
        <p style={{ margin: 0 }}>Controlled popover content.</p>
        <Button size="sm" onClick={() => setOpen(false)} style={{ marginTop: '0.75rem' }}>
          Dismiss
        </Button>
      </PopoverContent>
    </Popover>
  );
}

Installation

npx visor add popover

This copies two files into your project:

  • components/ui/popover/popover.tsx — the component
  • components/ui/popover/popover.module.css — the styles

Usage

import {
  Popover,
  PopoverTrigger,
  PopoverContent,
} from '@/components/ui/popover/popover';
import { Button } from '@/components/ui/button/button';

export default function Example() {
  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button variant="outline">Open</Button>
      </PopoverTrigger>
      <PopoverContent>
        <p>Place content here.</p>
      </PopoverContent>
    </Popover>
  );
}

API Reference

PopoverProps

PropTypeDefaultDescription
openbooleanControlled open state of the popover.
onOpenChange(open: boolean) => voidCallback when the open state changes.
defaultOpenbooleanfalseDefault open state for uncontrolled usage.
side'top' | 'right' | 'bottom' | 'left''bottom'Side of the trigger the popover appears on (on PopoverContent).
align'start' | 'center' | 'end''center'Alignment of the popover content relative to the trigger (on PopoverContent).
sideOffsetnumber4Distance in pixels between the trigger and the popover (on PopoverContent).
asChildbooleanfalseOn PopoverTrigger — merges props onto the immediate child element instead of rendering a <button>.
classNamestringAdditional CSS class names to merge onto PopoverContent.

Sub-components

ComponentElementPurpose
PopoverRootContext provider (wraps Radix Popover.Root)
PopoverTrigger<button>The element that opens the popover; use asChild to wrap a custom trigger
PopoverContentFloating panelThe popover panel; accepts side, align, and sideOffset
PopoverAnchorAny elementOptional anchor to position the popover relative to a different element than the trigger

Accessibility

  • Built on Radix UI Popoverrole="dialog" and aria-expanded are applied automatically.
  • Focus moves into the popover when it opens and returns to the trigger when it closes.
  • Pressing Escape closes the popover.
  • Clicking outside the popover closes it.
  • For non-modal popovers containing only non-interactive content (e.g., tooltips), consider HoverCard instead.