A rich popup anchored to a trigger, opened by click.

import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'
import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'

export default function PopoverDemo() {
  return (
    <Popover>
      <PopoverTrigger render={<Button variant="outline">Open popover</Button>} />
      <PopoverContent>
        <div className="grid gap-3">
          <div className="grid gap-1">
            <p className="text-sm font-medium">Dimensions</p>
            <p className="text-sm text-muted-foreground">Set the dimensions for the layer.</p>
          </div>
          <div className="grid grid-cols-3 items-center gap-2">
            <Label htmlFor="popover-width">Width</Label>
            <Input id="popover-width" defaultValue="100%" className="col-span-2 h-8" />
          </div>
          <div className="grid grid-cols-3 items-center gap-2">
            <Label htmlFor="popover-height">Height</Label>
            <Input id="popover-height" defaultValue="25px" className="col-span-2 h-8" />
          </div>
        </div>
      </PopoverContent>
    </Popover>
  )
}

Built on Base UI

Installation

pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/popover.json

Needs a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.

Popover imports cn() from lib/utils.ts — add it too if you don't have it yet:

import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Usage

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

<Popover>
  <PopoverTrigger render={<Button variant="outline">Open popover</Button>} />
  <PopoverContent>Set the dimensions for the layer.</PopoverContent>
</Popover>

API Reference

NameTypeDefaultDescription
open / onOpenChangeboolean / (open: boolean) => void—Control the open state from outside (set on Popover).
side'top' | 'bottom' | 'left' | 'right''bottom'Which side of the trigger the popover is positioned on (set on PopoverContent).
align'start' | 'center' | 'end''center'Alignment along the chosen side.
sideOffsetnumber8Gap between the trigger and the popover, in pixels.