RadCN
Overlaysreadycomponentready

Dropdown Menu

A menu overlay primitive for grouped commands, submenus, checkable items, radio choices, and app-owned cross-component actions.

Importimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from 'radcn/dropdown-menu'
Preview

Live package example

Render the four upstream Dropdown Menu examples through RadCN primitives and app-owned composition.

Example Parity

Render the four upstream Dropdown Menu examples through RadCN primitives and app-owned composition.

Preview

Checkbox persistence is app-owned state.

import { Dialog, DialogContent, DialogHeader, DialogTitle } from 'radcn/dialog'
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from 'radcn/dropdown-menu'

export function DropdownMenuExamples() {
  return (
    <>
      <DropdownMenu>
        <DropdownMenuTrigger>Open</DropdownMenuTrigger>
        <DropdownMenuContent>
          <DropdownMenuItem>Profile</DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
      <DropdownMenuCheckboxItem checked>Status Bar</DropdownMenuCheckboxItem>
      <DropdownMenuRadioGroup value="bottom">
        <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>
      </DropdownMenuRadioGroup>
      <Dialog>
        <DialogContent><DialogHeader><DialogTitle>Create New File</DialogTitle></DialogHeader></DialogContent>
      </Dialog>
    </>
  )
}

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 { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from 'radcn/dropdown-menu'

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

  • DropdownMenuTrigger receives aria-haspopup, aria-controls, aria-expanded, and keyboard opening behavior during enhancement.
  • DropdownMenuContent renders role="menu", with menuitem, menuitemcheckbox, and menuitemradio roles on interactive items.
  • Keyboard behavior covers Enter, Space, Arrow keys, Home, End, Escape, Tab, typeahead, submenu navigation, and disabled item skipping.
  • Dropdown Menu is non-modal in RadCN and does not lock body scroll; Dialog composition owns modal focus and scroll behavior separately.

Customization

  • DropdownMenu exposes public data-radcn-dropdown-menu hooks for root, trigger, portal, content, labels, groups, items, shortcuts, separators, checkbox items, radio groups, and submenus.
  • Checkbox and radio persistence, menu-to-dialog effects, and form values remain app-owned state rather than package-global callbacks.
  • Dialog, Field, Input, Textarea, Label, Button, and icon presentation remain separate composition surfaces.
  • Tailwind width, padding, flex, and alignment utilities map to RadCN classes, class, style, CSS variables, or small dependency-free browser enhancement.

Remix 3 Notes

  • React useState, onCheckedChange, onValueChange, and onSelect map to explicit RadCN props, server/route state, or app-owned browser enhancement.
  • modal={false} maps to RadCN Dropdown Menu non-modal behavior; Dialog remains the modal owner when composed from a menu item.
  • Button asChild maps to explicit DropdownMenuTrigger styling and composition rather than React Slot semantics.
  • lucide-react icons are app-owned presentation; Radix primitive types are read-only upstream evidence and not RadCN dependencies.
  • className maps to class, data-slot maps to data-radcn-* hooks, and vendor source remains read-only evidence.