Dropdown menu
A focused list of actions anchored to a trigger.
menuaction
Preview
Dropdown menu preview
Live · keyboard ready
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.
Row actions A kebab menu with a separated destructive item.
Row actions
A kebab menu with a separated destructive item. preview
Live · keyboard ready
quarterly-report.pdf
row-actions-a-kebab-menu-with-a-separated-destructive-item-.tsxtsx
Keyboard interactions
| Keys | Action |
|---|---|
| Enter / Space / ArrowDown | Opens the menu from the trigger. |
| ArrowDown / ArrowUp | Moves between items, looping at the ends. |
| Home / End | Jumps to the first or last item. |
| Escape | Closes 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.