Files
skills/docs/ui/react/react-ui/src/components/dropdown-menu/dropdown-menu.md
2026-05-29 08:20:56 +01:00

8.8 KiB

DropdownMenu

(no submodules)

- dropdown-menu.variants — `dropdownMenuContentVarian…
  • dropdown-menu.variants — dropdownMenuContentVariants, dropdownMenuItemVariants, dropdownMenuLabelVariants, dropdownMenuSeparatorVariants…

  • dropdown-menu.variants — `dropdownMenuContentVarian…

  • dropdown-menu.variants — dropdownMenuContentVariants, dropdownMenuItemVariants, dropdownMenuLabelVariants, dropdownMenuSeparatorVariants…

  • dropdown-menu.variants — `dropdownMenuContentVarian…

  • dropdown-menu.variants — dropdownMenuContentVariants, dropdownMenuItemVariants, dropdownMenuLabelVariants, dropdownMenuSeparatorVariants…

  • dropdown-menu.variants — `dropdownMenuContentVarian…

  • dropdown-menu.variants — dropdownMenuContentVariants, dropdownMenuItemVariants, dropdownMenuLabelVariants, dropdownMenuSeparatorVariants…

  • dropdown-menu.variants — dropdownMenuContentVariants, dropdownMenuItemVariants, dropdownMenuLabelVariants, dropdownMenuSeparatorVariants…

Purpose

<DropdownMenu> and its sub-components (<DropdownMenuTrigger>, <DropdownMenuContent>, <DropdownMenuItem>, <DropdownMenuGroup>, <DropdownMenuLabel>, <DropdownMenuSeparator>, <DropdownMenuShortcut>, <DropdownMenuCheckboxItem>, <DropdownMenuRadioGroup>, <DropdownMenuRadioItem>, <DropdownMenuSub>, <DropdownMenuSubTrigger>, <DropdownMenuSubContent>, <DropdownMenuPortal>) are the chassis dropdown-menu primitive built on @radix-ui/react-dropdown-menu. Radix supplies the WAI-ARIA menu semantics (role="menu", role="menuitem", arrow-key roving focus, type-ahead search, Escape closes, focus-trap while open, restore-focus to the trigger on close), and the chassis layers cva slots, theme overrides, and a translated <DropdownMenuShortcut> aria-keyshortcuts attribute on top.

Composition rule (shadcn skill rule): items typically sit inside a <DropdownMenuGroup> so screen-readers announce them as one set. Single ungrouped items at the top level are also acceptable. Sub-menus pair <DropdownMenuSubTrigger> with <DropdownMenuSubContent> inside a <DropdownMenuSub>.

Features

  • WAI-ARIA menu semantics from Radix.
  • Arrow-key roving focus + type-ahead search.
  • Escape closes; click-outside dismisses; restore-focus to the trigger on close.
  • Auto-portalled <DropdownMenuContent> (matches shadcn upstream — consumers do not need to remember <DropdownMenuPortal>).
  • <DropdownMenuShortcut> accepts an ariaKeyShortcutsKey translation key so the localised shortcut announcement reaches assistive tech.
  • <DropdownMenuCheckboxItem> / <DropdownMenuRadioGroup> / <DropdownMenuRadioItem> with 32-px gutter for the indicator.
  • <DropdownMenuSub> for nested sub-menus with a chevron indicator (RTL-flipped via rtl:rotate-180).
  • inset variant on <DropdownMenuItem> / <DropdownMenuLabel> / <DropdownMenuSubTrigger> aligns with checkbox/radio rows.
  • All sub-components forward refs to their underlying Radix elements.

Usage: Basic Example

import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuGroup,
    DropdownMenuItem,
    DropdownMenuTrigger,
} from "@suaveplan/react-ui";

export function UserMenu() {
    return (
        <DropdownMenu>
            <DropdownMenuTrigger>Open menu</DropdownMenuTrigger>
            <DropdownMenuContent>
                <DropdownMenuGroup>
                    <DropdownMenuItem>Profile</DropdownMenuItem>
                    <DropdownMenuItem>Settings</DropdownMenuItem>
                    <DropdownMenuItem>Sign out</DropdownMenuItem>
                </DropdownMenuGroup>
            </DropdownMenuContent>
        </DropdownMenu>
    );
}

Usage: Advanced Example

import {
    Button,
    DropdownMenu,
    DropdownMenuCheckboxItem,
    DropdownMenuContent,
    DropdownMenuGroup,
    DropdownMenuItem,
    DropdownMenuLabel,
    DropdownMenuRadioGroup,
    DropdownMenuRadioItem,
    DropdownMenuSeparator,
    DropdownMenuShortcut,
    DropdownMenuSub,
    DropdownMenuSubContent,
    DropdownMenuSubTrigger,
    DropdownMenuTrigger,
} from "@suaveplan/react-ui";
import { useState } from "react";

export function EditorMenu() {
    const [showLineNumbers, setShowLineNumbers] = useState(true);
    const [theme, setTheme] = useState<"light" | "dark">("light");

    return (
        <DropdownMenu>
            <DropdownMenuTrigger asChild>
                <Button variant="outline">View</Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent>
                <DropdownMenuLabel>Editor</DropdownMenuLabel>
                <DropdownMenuSeparator />
                <DropdownMenuGroup>
                    <DropdownMenuItem>
                        Save
                        <DropdownMenuShortcut ariaKeyShortcutsKey="app.shortcuts.save">
                            ⌘S
                        </DropdownMenuShortcut>
                    </DropdownMenuItem>
                </DropdownMenuGroup>
                <DropdownMenuSeparator />
                <DropdownMenuCheckboxItem
                    checked={showLineNumbers}
                    onCheckedChange={(checked) =>
                        setShowLineNumbers(Boolean(checked))
                    }
                >
                    Line numbers
                </DropdownMenuCheckboxItem>
                <DropdownMenuRadioGroup
                    value={theme}
                    onValueChange={(v) => setTheme(v as "light" | "dark")}
                >
                    <DropdownMenuRadioItem value="light">
                        Light theme
                    </DropdownMenuRadioItem>
                    <DropdownMenuRadioItem value="dark">
                        Dark theme
                    </DropdownMenuRadioItem>
                </DropdownMenuRadioGroup>
                <DropdownMenuSub>
                    <DropdownMenuSubTrigger>Export</DropdownMenuSubTrigger>
                    <DropdownMenuSubContent>
                        <DropdownMenuItem>PDF</DropdownMenuItem>
                        <DropdownMenuItem>HTML</DropdownMenuItem>
                        <DropdownMenuItem>Markdown</DropdownMenuItem>
                    </DropdownMenuSubContent>
                </DropdownMenuSub>
            </DropdownMenuContent>
        </DropdownMenu>
    );
}

API Reference

<DropdownMenu>

The Radix Root. Standard Radix Root props (open, defaultOpen, onOpenChange, modal, dir).

<DropdownMenuTrigger>

Wraps the Radix Trigger (renders a <button> or polymorphically the child via asChild).

<DropdownMenuContent>

The floating menu surface. Auto-portalled. Accepts standard Radix Content props (side, align, sideOffset, alignOffset, collisionPadding, etc.).

<DropdownMenuItem>

A single menu item.

Prop Type Default Description
inset boolean false Adds 32-px left gutter.
disabled boolean false Skips in keyboard nav and ignores activation.
onSelect (event: Event) => void none Fires on activation.

<DropdownMenuGroup>, <DropdownMenuLabel>, <DropdownMenuSeparator>

Standard menu structure. <DropdownMenuLabel> accepts an inset prop for alignment.

<DropdownMenuShortcut>

Keyboard-shortcut hint pinned at the end of an item.

Prop Type Default Description
ariaKeyShortcutsKey TranslationKey none When present, sets aria-keyshortcuts to the translated shortcut.

<DropdownMenuCheckboxItem>, <DropdownMenuRadioGroup>, <DropdownMenuRadioItem>

Standard Radix props (checked, onCheckedChange, value, onValueChange).

<DropdownMenuSub>, <DropdownMenuSubTrigger>, <DropdownMenuSubContent>

Nested sub-menu. <DropdownMenuSubTrigger> accepts an inset prop and renders a chevron icon (RTL-flipped via rtl:rotate-180).

Implementation Notes

  • The chassis NEVER assigns a numeric z-index to the menu — Radix portals handle stacking.
  • The check / dot indicators sit at start-2 (logical property) so they flip correctly in RTL contexts.
  • motion-reduce:animate-none collapses the open/close transition for prefers-reduced-motion: reduce.
  • The <DropdownMenuShortcut> separates the visible text (passed as children) from the localised announcement (ariaKeyShortcutsKey) so a glyph like ⌘S can be shown to sighted users while screen-readers hear "Command S" or the localised equivalent.
  • Per the shadcn skill rule, items in groups MUST live inside <DropdownMenuGroup> for correct screen-reader announcement.
  • <DropdownMenuContent> auto-portals via <DropdownMenuPortal> so consumers do not have to remember to wrap manually — matches shadcn upstream's convention.