React Dropdown Component Examples
Drop-in React Dropdown examples: actions menu, right-aligned, grouped items, user avatar menu, and table-row kebab. Zero runtime deps, dot notation API.
A dropdown is the right surface for short lists of click-driven actions — Edit, Duplicate, Delete on a Table row, the user-avatar menu in a header, a kebab on a Card. The Dropdown component in Drivn is a plain React file of about 168 lines that ships zero runtime UI dependencies: useState tracks open and closed, a mousedown listener on document closes the menu when you click outside, and a CSS transition on opacity and scale handles the entrance. It uses dot notation — Dropdown.Trigger opens, Dropdown.Content renders the panel, and Dropdown.Item is a single action with an icon prop and a destructive flag.
This page collects the patterns that come up in shipped UIs. Each example is copy-paste ready and uses the same @/components/ui/dropdown import path the Drivn CLI installs under, so the snippets compile the moment you run npx drivn add dropdown. The trigger renders Drivn's Button with variant="outline" and rounded="md" internally, so consumers do not need to compose a styled handle — any children passed to Dropdown.Trigger render as the button label. The align prop on the root accepts left (default) or right and picks the matching styles.align utility on Dropdown.Content.
If your menu needs full keyboard navigation, submenus, or checkbox and radio items, the Drivn Dropdown does not ship those — see Drivn vs shadcn Dropdown for the comparison and pick Radix through shadcn for that surface. The examples below stay focused on the click-driven shape: a basic actions menu with icons, a right-aligned menu, grouped items with labels and separators, a user-avatar menu in a header, and a table-row kebab menu.
Grouped items with labels and separators
For menus with more than four or five actions, group related items together. Dropdown.Group wraps a section with a py-1 rhythm, Dropdown.Label renders a muted heading at px-3 py-1.5 text-xs font-medium text-muted-foreground, and Dropdown.Separator draws a 1px horizontal line via my-1 h-px bg-border. The pattern matches how Gmail, Linear, and Notion structure their context menus — a label sets context, the items underneath act on that context, a separator breaks to the next group.
Keep groups short — three to five items max — and label each one with one or two words. If a group grows beyond five items, the menu is doing too much; split the actions into a Tabs or Sidebar instead. The Dropdown.Group element exists for visual rhythm only; it has no semantic role attached.
1 import { Dropdown } from "@/components/ui/dropdown" 2 import { Edit, Copy, Share2, Archive, Trash2 } from "lucide-react" 3 4 export default function Page() { 5 return ( 6 <Dropdown> 7 <Dropdown.Trigger>Manage</Dropdown.Trigger> 8 <Dropdown.Content> 9 <Dropdown.Group> 10 <Dropdown.Label>Edit</Dropdown.Label> 11 <Dropdown.Item icon={Edit}>Rename</Dropdown.Item> 12 <Dropdown.Item icon={Copy}>Duplicate</Dropdown.Item> 13 </Dropdown.Group> 14 <Dropdown.Separator /> 15 <Dropdown.Group> 16 <Dropdown.Label>Share</Dropdown.Label> 17 <Dropdown.Item icon={Share2}>Share link</Dropdown.Item> 18 </Dropdown.Group> 19 <Dropdown.Separator /> 20 <Dropdown.Group> 21 <Dropdown.Label>Danger zone</Dropdown.Label> 22 <Dropdown.Item icon={Archive}>Archive</Dropdown.Item> 23 <Dropdown.Item icon={Trash2} destructive> 24 Delete 25 </Dropdown.Item> 26 </Dropdown.Group> 27 </Dropdown.Content> 28 </Dropdown> 29 ) 30 }
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
npx drivn@latest createRequires Node 18+. Works with npm, pnpm, and yarn.
Frequently asked questions
You do not need to — Dropdown.Item wraps your onClick and calls setOpen(false) automatically after your handler runs. The wrapper lives inside the registry source: each Item button invokes the consumer's onClick, then closes the menu in the same click handler. If you need the menu to stay open after an item-click (rare, but useful for confirm-then-act flows), edit the local copy at @/components/ui/dropdown and remove the setOpen(false) line from the Item handler, or skip Dropdown.Item and render a plain <button> inside Dropdown.Content.
The trigger renders Drivn's Button component under the hood with variant="outline" and rounded="md" wired in. Whatever children you pass become the button label, so an icon, an avatar, or a mixed icon-plus-text label all work — you just give up the ability to render a non-button element at the trigger position. If you need the trigger to be a link, an avatar without the outline ring, or a custom element, edit the Trigger function inside @/components/ui/dropdown after install. The file lives in your repo, and the change is local to your project.
No — Dropdown.Item is a single flat action, and there is no Dropdown.Sub or Dropdown.SubContent in the registry source. The component is designed for short, click-driven menus where every action lives at the top level. If your menu needs hierarchical actions or a Files > Recent > Yesterday-style cascade, reach for shadcn/ui's Radix-backed DropdownMenu for that specific surface — see Drivn vs shadcn Dropdown for the comparison. The two libraries can coexist in the same project.
The dropdown content is positioned with absolute top-full mt-1 on styles.content and does not portal out of the DOM. That means an overflow: hidden ancestor can clip the menu when it opens. The fix is to give the ancestor overflow: visible for that one container, or move the dropdown outside the clipped subtree. If portaling is a hard requirement — long lists of items inside a virtualised table is the classic case — pick the Radix-backed DropdownMenu through shadcn/ui, which renders its content through a portal by default.
The Dropdown file starts with "use client" because it manages state with useState and attaches a mousedown listener through useEffect. You can import it from a Server Component, but it renders on the client. Next.js draws the client boundary correctly based on the directive at the top of the file — no manual configuration needed in your layout or page. Render the trigger and content inside any server-rendered page and the dropdown hydrates on the client automatically.

