Dropdown Menu
A menu of actions triggered by a button. Rises with overlay depth; items highlight on hover and keyboard navigation. Submenus nest inside the popup rather than flying out beside it, so depth is unlimited and costs no horizontal room.
tsx
import { Button } from "@/registry/seam/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/registry/seam/ui/dropdown-menu"
export default function DropdownMenuDemo() {
return (
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant="outline">Open menu</Button>}
/>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Log out</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}bunx --bun @seamui/cli@latest add dropdown-menuNotes
- Full keyboard support — arrows, Home/End, typeahead, Escape — with
role="menu"semantics; Base UI handles positioning and collision. - Submenus drill in place: the level replaces the one below it and the popup springs to the new size. Levels you drill past keep their state, so an uncontrolled checkbox or radio group is still set the way you left it when you come back. Nesting is unlimited — a
DropdownMenuSubinside aDropdownMenuSubContentis just the next level. - Every nested level opens with a back row labelled from its trigger. ArrowRight or Enter drills in; ArrowLeft, Escape, or the back row steps out, returning focus to the trigger you left through. Escape only closes the menu once you are back at the root.
- Checkbox and radio items ship in the same file when a menu needs selectable state.
Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.