Dropdown menu

A focused list of actions anchored to a trigger.

menuaction
Preview
Dropdown menu preview

When to use

  • A list of commands behind a labelled button, such as Rename, Duplicate, and Delete.
  • Row or card actions where a visible trigger is clearer than right-click.
  • Short grouped menus with separators and one destructive item at the end.

When not to use

  • Use split-button when one command is the default.
  • Use context-menu for right-click actions on content.
  • Use user-menu for the account menu, and command-palette for searching many commands.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dropdown-menu",
  "type": "registry:ui",
  "title": "Dropdown menu",
  "description": "A focused list of actions anchored to a trigger.",
  "categories": [
    "actions"
  ],
  "dependencies": [
    "@radix-ui/react-dropdown-menu",
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/dropdown-menu/dropdown-menu.tsx",
      "type": "registry:component",
      "target": "@components/manicat/dropdown-menu/dropdown-menu.tsx"
    },
    {
      "path": "registry/components/dropdown-menu/dropdown-menu.module.css",
      "type": "registry:component",
      "target": "@components/manicat/dropdown-menu/dropdown-menu.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/dropdown-menu",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/dropdown-menu",
    "markdown": "https://uiarc.dev/components/dropdown-menu/markdown",
    "tags": [
      "menu",
      "action"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { useEffect, useState } from "react";
import { MoreHorizontal, Share2, Star, Trash2, Undo2 } from "lucide-react";
import { DropdownMenu } from "@/components/manicat/dropdown-menu/dropdown-menu";

export function DropdownMenuExample() {
  const [opened, setOpened] = useState<string | null>(null);

  return (
    <div className="flex flex-col items-start gap-3">
      <DropdownMenu
        label="Row actions"
        icon={<MoreHorizontal size={16} />}
        items={[
          { label: "Rename", onSelect: () => setOpened("Rename") },
          { label: "Duplicate" },
          { label: "Move to archive", separatorBefore: true },
          { label: "Delete", destructive: true, onSelect: () => setOpened("Delete") },
        ]}
      />
      {opened ? <span className="text-sm text-(color:--text-muted)">Selected: {opened}</span> : null}
    </div>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Keyboard interactions

KeysAction
Enter / Space / ArrowDownOpens the menu from the trigger.
ArrowDown / ArrowUpMoves between items, looping at the ends.
Home / EndJumps to the first or last item.
EscapeCloses the menu and returns focus to the trigger.

Accessibility

  • Built on Radix DropdownMenu: the trigger gets aria-haspopup and aria-expanded, items get menuitem roles and typeahead.
  • Icons and the highlight are aria-hidden; destructive items are marked by color and should say what they destroy.
  • Disabled items are skipped by the keyboard.

Motion

  • The highlight glides between items on a snappy spring for the pointer and jumps instantly for the keyboard.
  • The menu scales in from the trigger and items fade in with a short stagger.
  • Reduced motion removes the menu transform and highlight glide, keeping a quick opacity fade.

Responsive behavior

  • The trigger label ellipsizes within max-width 100%, so it shrinks inside narrow toolbars instead of overflowing.
  • The menu uses Radix collision handling with 12px padding and a 12rem minimum width, flipping away from viewport edges.
  • Hover styles apply only on fine pointers; touch taps select without a stuck highlight.

Performance

  • Menu content renders in a portal only while open; items are not virtualized, so keep lists short.
  • The menu has a translucent backdrop blur, which drops to a solid surface under prefers-reduced-transparency.

Notes for AI

  • Default choice for a list of commands behind a button. Use split-button when one command is the default, and context-menu for right-click on content.
  • Group items with separatorBefore; put destructive items last.
  • Items are data, not children, so build the array from your actions.