RadCN
Overlaysreadycomponentready

Popover

A dependency-free click popover with explicit trigger, portal, content, placement, dismissal, and form-composition hooks.

Importimport { Popover, PopoverContent, PopoverPortal, PopoverTrigger } from 'radcn/popover'
Preview

Live package example

Render the upstream dimensions form with an outline trigger, 20rem content, labelled inputs, and default values.

Popover Demo

Render the upstream dimensions form with an outline trigger, 20rem content, labelled inputs, and default values.

Preview
import { Input } from 'radcn/input'
import { Label } from 'radcn/label'
import { Popover, PopoverContent, PopoverPortal, PopoverTrigger } from 'radcn/popover'

export function PopoverDemo() {
  return (
    <Popover id="popover-demo">
      <PopoverTrigger class="radcn-button radcn-button--outline">
        Open popover
      </PopoverTrigger>
      <PopoverPortal>
        <PopoverContent class="w-80" style="width:20rem;">
          <div class="grid gap-4">
            <div class="space-y-2">
              <h4 class="leading-none font-medium">Dimensions</h4>
              <p class="text-sm text-muted-foreground">
                Set the dimensions for the layer.
              </p>
            </div>
            <div class="grid gap-2">
              <div class="grid grid-cols-3 items-center gap-4">
                <Label for="width">Width</Label>
                <Input id="width" value="100%" class="col-span-2 h-8" />
              </div>
              <div class="grid grid-cols-3 items-center gap-4">
                <Label for="maxWidth">Max. width</Label>
                <Input id="maxWidth" value="300px" class="col-span-2 h-8" />
              </div>
              <div class="grid grid-cols-3 items-center gap-4">
                <Label for="height">Height</Label>
                <Input id="height" value="25px" class="col-span-2 h-8" />
              </div>
              <div class="grid grid-cols-3 items-center gap-4">
                <Label for="maxHeight">Max. height</Label>
                <Input id="maxHeight" value="none" class="col-span-2 h-8" />
              </div>
            </div>
          </div>
        </PopoverContent>
      </PopoverPortal>
    </Popover>
  )
}

Installation

Intended future install command. RadCN is private and not published to npm yet, so this snippet documents the target user-facing API rather than something external consumers can run today.

pnpm add radcn # intended future package
import { Popover, PopoverContent, PopoverPortal, PopoverTrigger } from 'radcn/popover'

Theming

RadCN tokens read the resolved theme from the document. Store the user's preference separately, then resolve system preferences to a concrete light or dark theme before setting package tokens.

<html data-radcn-theme-mode="system" data-radcn-theme="dark">
  ...
</html>

Accessibility

  • PopoverTrigger renders a native button with aria-haspopup="dialog" and browser-enhanced aria-expanded and aria-controls state.
  • Popover content moves through PopoverPortal during browser enhancement while preserving visible labelled form controls.
  • The dimensions form uses real Label and Input associations for width, maxWidth, height, and maxHeight fields.
  • Popover remains non-modal: Escape, outside click, and close behavior do not lock document scrolling.

Customization

  • Root, trigger, portal, content, anchor, close, header, title, and description expose public data-radcn-popover hooks and package classes.
  • PopoverTrigger asChild and Button variant="outline" map to explicit trigger styling with RadCN button classes, without Slot or React child cloning.
  • PopoverContent className="w-80" maps to class/style/CSS variable evidence for a 20rem content width.
  • default align center and sideOffset 4 remain explicit content props and data hooks; apps can tune side, align, offset, width, and tokens.
  • Input and Label composition remains app-owned form markup inside PopoverContent, not Popover package state.

Remix 3 Notes

  • use client, React component props, and Radix Popover primitives map to server-rendered RadCN markup plus scoped enhancePopover browser behavior.
  • Radix implicit Popover portal maps to explicit PopoverPortal composition so portal ownership is visible to authors and tests.
  • className maps to class, cn maps to explicit class composition, and data-slot maps to public data-radcn-popover* hooks.
  • Tailwind grid, gap, width, col-span, height, leading, font, text-sm, muted foreground, transition, data-state, and data-side utilities map to package CSS, classes, style, CSS variables, and app-owned CSS.
  • Input defaultValue maps to RadCN Input value for deterministic server-rendered default form values.
  • Vendor source remains read-only evidence and is not imported by RadCN.