Anchored action menu with header, body, and footer. Rows compose List Item. Prefer Option List for pickers that keep a selected value.
Also known as: action menu, three dot menu, kebab menu, profile menu, account menu, overflow menu, button menu
Install with the CLI, or copy the component source into your project.
Add dropdown-menu (npm)
1npx --yes -p github:itsvigneshv/default-file-ui#main df-ui add dropdown-menu
Inline account menu with avatar header, actions, and footer.
Header without avatar. Title and description use size and color chrome.
Header meta Badge under the email and trailing Badge on the right.
Content shadow chrome. Off by default; pass a kit elevation token for depth.
Content itemSize sm on profile and overflow compositions.
Stacked List Item trigger with a portaled workspace menu and selected checks.
Click Profile to open the anchored account menu.
Batch menu with status Header, Kbd shortcuts, and destructive delete.
Section labels, shortcuts, submenu, and preference checks. Body scrollable with maxHeight.
Overflow menu with destination, account, and sign-out groups.
side and align placement, including align auto with collision avoidance.
Bottom
Top
Left and right
Content-aware
Anchored action menu for profile menus, workspace switchers, three-dot menus, and toolbar actions. Compose Content with Header, Body, and Footer. Items fire onSelect and close by default. Rows compose List Item. Prefer Option List when the panel should keep a selected value without running a command.
| Prop | Type | Default | Notes |
|---|---|---|---|
| open | boolean | - | Controlled open state. Placement still uses DropdownMenuTrigger when something else sets open. |
| defaultOpen | boolean | false | Initial open state when open is not passed. The menu manages open after that. |
| onOpenChange | (open: boolean) => void | - | Called when open changes from the trigger, dismiss, item select, or parent updates. |
| closeOnSelect | boolean | true | Close the menu after an item activates. Set false to keep the menu open. |
| children | ReactNode | - | Usually DropdownMenuTrigger and DropdownMenuContent. |
Placement anchor and toggle. Click, Enter, and Space toggle. ArrowDown opens. Escape closes when open.
| Prop | Type | Default | Notes |
|---|---|---|---|
| render | ReactElement | - | Host element for the trigger. Toggles open and marks the anchor. Use a Button, icon button, or avatar control. |
| children | ReactNode | - | Trigger content when not using render. |
| className | string | - | Additional styles on the trigger host. |
Anchored surface shell. Place Header, Body, and Footer as children. Handles arrows, Home, End, typeahead, Escape, and Tab.
| Prop | Type | Default | Notes |
|---|---|---|---|
| side | "top" | "bottom" | "left" | "right" | "bottom" | Preferred side of the trigger. Combine with align for corners. With collisionAvoidance, the panel can flip when space is tight. |
| align | "start" | "center" | "end" | "auto" | "end" | Alignment along the placement side. auto picks start, center, or end from available space. |
| sideOffset | number | 8 | Gap between the trigger and the menu, in pixels. |
| alignOffset | number | 0 | Shift along the alignment axis, in pixels. |
| width | "hug" | "fill" | string | "hug" | Panel width. hug sizes to content. fill matches the trigger when portaled, or the parent when portal is false. Pass a CSS length for a fixed panel. |
| itemSize | "xs" | "sm" | "md" | "lg" | - | Default List Item density for rows in this panel. Use sm for a compact menu. Per-item size overrides this. |
| matchTriggerWidth | boolean | true when width is fill, otherwise false | Match the menu width to the trigger when portaled. Defaults to true when width is fill. |
| portal | boolean | true | Render in a document body portal. Set false for an inline panel. Outside dismiss runs only when portal is true. |
| dismissOnScroll | boolean | true | Close when the page scrolls outside the menu. |
| followScroll | boolean | true | Keep the panel anchored to the trigger while the page scrolls. |
| collisionAvoidance | boolean | true | Flip placement and cap height to the viewport when space is tight. Body scrolls when rows overflow. Set false to keep the requested side and align. |
| animated | boolean | true | Open and close motion from the placement side. Set false for an instant panel. prefers-reduced-motion disables motion. |
| openDuration | number | - | Open motion duration in milliseconds. Defaults to --df-dropdown-menu-open-duration. |
| closeDuration | number | - | Close motion duration in milliseconds. Defaults to --df-dropdown-menu-close-duration. |
| background | string | - | Panel fill. Prefer tokens such as var(--popover). Sets --df-dropdown-menu-bg. |
| foreground | string | - | Panel text color. Prefer tokens such as var(--popover-foreground). Sets --df-dropdown-menu-fg. |
| borderColor | string | - | Border color. Prefer tokens such as var(--border). Sets --df-dropdown-menu-border-color. |
| borderWidth | string | - | Border width. Prefer tokens such as var(--border-width-hairline). Sets --df-dropdown-menu-border-width. |
| borderStyle | string | - | Border style. Prefer solid. Sets --df-dropdown-menu-border-style. |
| radius | string | - | Corner radius. Prefer tokens such as var(--radius-2xl). Sets --df-dropdown-menu-radius. |
| shadow | string | false | none | Panel box-shadow. Off by default. Pass a kit elevation token such as var(--df-shadow-md), or none or false to stay flat. Sets --df-dropdown-menu-shadow. |
| dividerColor | string | - | Header and separator hairline color. Prefer var(--border). Sets --df-dropdown-menu-divider-color. |
| padding / paddingX / paddingY / sides | string | - | Shell inset around header, body, and footer. Sets --df-dropdown-menu-padding-*. Prefer spacing tokens. |
| gap | string | - | Gap between header, body, and footer. Sets --df-dropdown-menu-gap. |
| children | ReactNode | - | Usually DropdownMenuHeader, DropdownMenuBody, and DropdownMenuFooter. |
Top section above the body with an edge-to-edge bottom rule. Use for profile blocks or selection status. Title becomes the menu accessible name when present.
| Prop | Type | Default | Notes |
|---|---|---|---|
| leading | ReactNode | false | - | Leading media such as Avatar. Omit or pass false to hide it. |
| title | ReactNode | - | Primary label. Truncates with an ellipsis when the panel is too narrow. |
| description | ReactNode | - | Supporting line under the title, usually an email. Truncates when narrow. |
| meta | ReactNode | - | Below the description in the copy column. Prefer Badge for plan or status. |
| trailing | ReactNode | - | End-aligned mark on the header row. Prefer Badge for a count or status chip. |
| background | string | - | Header fill. Prefer tokens. Sets --df-dropdown-menu-header-bg. |
| gap | string | - | Gap between leading, copy, and trailing. Sets --df-dropdown-menu-header-gap. |
| titleColor | string | - | Title color. Sets --df-dropdown-menu-title-color. |
| titleSize | string | - | Title font size. Sets --df-dropdown-menu-title-size. |
| titleWeight | string | - | Title font weight. Sets --df-dropdown-menu-title-weight. |
| descriptionColor | string | - | Description color. Sets --df-dropdown-menu-description-color. |
| descriptionSize | string | - | Description font size. Sets --df-dropdown-menu-description-size. |
| dividerColor | string | - | Header bottom rule color. Sets --df-dropdown-menu-divider-color for this header. |
| padding / paddingX / paddingY / sides | string | - | Header inset. Sets --df-dropdown-menu-header-padding-*. Prefer spacing tokens. |
| children | ReactNode | - | Extra header content below the title row. |
Middle section with role menu. Place action rows, labels, and separators here. Uses the kit ScrollArea; the thumb appears when rows overflow.
| Prop | Type | Default | Notes |
|---|---|---|---|
| gap | string | - | Gap between rows. Sets --df-dropdown-menu-body-gap. |
| scrollable | boolean | false | Apply maxHeight for an intentional height cap. Collision avoidance already scrolls when the viewport is tight. |
| maxHeight | string | number | var(--df-dropdown-menu-body-max-height) | Height constraint when scrollable is true. Prefer tokens. |
| scrollThumbGap | number | - | Space on each side of the scrollbar thumb, in pixels. Sets --df-dropdown-menu-scroll-thumb-gap. |
| padding / paddingX / paddingY / sides | string | - | Body inset inside the shell. Sets --df-dropdown-menu-body-padding-*. Prefer spacing tokens. |
| children | ReactNode | - | DropdownMenuItem rows, plus optional labels and separators. |
| className | string | - | Additional styles on the body. |
Action row built on List Item. Place inside DropdownMenuBody. Activates onSelect, then closes when closeOnSelect is true.
| Prop | Type | Default | Notes |
|---|---|---|---|
| onSelect | (event: Event) => void | - | Called when the item activates. Call event.preventDefault() to keep the menu open even when closeOnSelect is true. |
| tone | "default" | "success" | "destructive" | "default" | Visual tone. Use destructive for remove actions. |
| variant | "accent" | "muted" | "accent" | List Item color recipe. muted uses muted-foreground for quieter rows. |
| leading | ReactNode | false | - | Leading icon or status mark. Passed to List Item. |
| shortcut | string | - | Unicode keyboard hint in the trailing slot via kit Kbd, such as ⌘K. Display only; host owns key bindings. |
| trailing | ReactNode | - | Trailing content. Submenu triggers add a chevron when omitted. |
| secondary | ReactNode | - | Secondary text under the label. |
| layout | "inline" | "stacked" | "columns" | "inline" | List Item copy layout. |
| selected | boolean | false | Shows the end check when indicator is not overridden. Use for preference rows and the active workspace. |
| indicator | boolean | - | Force the end check on or off. Defaults to true when selected is true. |
| leadingFit | "icon" | "content" | "icon" | Leading track sizing. Use content for Avatar and other non-icon marks. |
| asChild | boolean | false | Render the child element as the row host, usually a link. |
| disabled | boolean | false | Disable activation and skip keyboard focus. |
| readOnly | boolean | false | Presentational row. Not activatable and skipped for keyboard focus. |
| size | "xs" | "sm" | "md" | "lg" | "md, or Content itemSize when set" | List Item density for this row. Defaults to Content itemSize when set, otherwise md. |
| padding / gap / fontSize / background / foreground / radius / … | string | - | List Item chrome. Prefer tokens. See List Item. |
| children | ReactNode | - | Item label. |
Keyboard hint for menu rows. Renders kit Kbd at size sm. Prefer the shortcut prop on DropdownMenuItem.
| Prop | Type | Default | Notes |
|---|---|---|---|
| children | ReactNode | - | Unicode shortcut label such as ⌘K. Textual forms such as Ctrl+K are not parsed. |
| className | string | - | Additional styles on the shortcut host. |
Hairline rule between item groups inside the body.
| Prop | Type | Default | Notes |
|---|---|---|---|
| dividerColor | string | - | Hairline color for this rule. Prefer tokens such as var(--border). Sets --df-dropdown-menu-divider-color. |
| marginBlock | string | - | Vertical space around the rule. Prefer spacing tokens. Sets --df-dropdown-menu-separator-margin-block. |
| className | string | - | Additional styles on the separator. |
Non-interactive group label above a set of items in the body.
| Prop | Type | Default | Notes |
|---|---|---|---|
| color | string | - | Label color. Prefer tokens. Sets --df-dropdown-menu-label-color. |
| fontSize | string | var(--df-text-11) | Label type size. Prefer tokens. Sets --df-dropdown-menu-label-size. |
| padding / paddingX / paddingY / sides | string | - | Label inset. Sets --df-dropdown-menu-label-padding-*. Prefer spacing tokens. |
| children | ReactNode | - | Label copy. |
Hover-open nested action branch. Place a DropdownMenuItem trigger and DropdownMenuSubContent as children. Motion defaults come from CSS tokens and can be overridden here or on SubContent.
| Prop | Type | Default | Notes |
|---|---|---|---|
| open | boolean | - | Controlled submenu open state. |
| defaultOpen | boolean | false | Initial open state when open is not passed. |
| onOpenChange | (open: boolean) => void | - | Called when the submenu open state changes. |
| animated | boolean | true | Open and close motion for this branch. Set false for an instant panel. |
| openDuration | number | - | Open motion duration in milliseconds. Defaults to --df-dropdown-menu-submenu-open-duration. |
| closeDuration | number | - | Close motion duration in milliseconds. Defaults to --df-dropdown-menu-submenu-close-duration. |
| closeDelay | number | 60 | Hover leave delay before the submenu closes, in milliseconds. |
| children | ReactNode | - | Trigger item and DropdownMenuSubContent. |
Nested menu surface. Defaults to the right of the trigger row and portals to the document body. Shares Content surface chrome. Placement and motion can be set per panel.
| Prop | Type | Default | Notes |
|---|---|---|---|
| side | "top" | "bottom" | "left" | "right" | "right" | Preferred side of the trigger row. |
| sideOffset | number | 4 | Gap between the trigger row and the nested panel, in pixels. |
| align | "start" | "center" | "end" | "auto" | "start" | Alignment along the placement side. |
| alignOffset | number | 0 | Shift along the alignment axis, in pixels. |
| portal | boolean | true | Render in a document body portal. |
| animated | boolean | inherits DropdownMenuSubmenu.animated | Per-panel motion override. Set false for an instant panel on this surface. |
| openDuration | number | inherits DropdownMenuSubmenu.openDuration | Per-panel open duration in milliseconds. Defaults to the submenu token when unset. |
| closeDuration | number | inherits DropdownMenuSubmenu.closeDuration | Per-panel close duration in milliseconds. Defaults to the submenu token when unset. |
| shadow | string | false | none | Nested panel box-shadow. Same contract as DropdownMenuContent shadow. |
| background / foreground / borderColor / borderWidth / borderStyle / radius / dividerColor | string | - | Surface chrome. Same contract as DropdownMenuContent. Prefer tokens. |
| children | ReactNode | - | Nested DropdownMenuItem rows and separators. |
Muted meta row under the body, such as version or legal copy. Built on List Item. Defaults to readOnly. Use asChild for a link host.
| Prop | Type | Default | Notes |
|---|---|---|---|
| leading | ReactNode | false | false | Optional leading mark. Defaults to no leading slot. |
| size | "xs" | "sm" | "md" | "lg" | "sm" | List Item density. |
| readOnly | boolean | true | Presentational meta. Defaults to false when asChild is true so a link stays interactive. |
| asChild | boolean | false | Render the child element as the row host, usually a link. |
| padding / paddingX / paddingY / sides | string | - | List Item chrome padding. Prefer spacing tokens. See List Item. |
| background / foreground / fontSize / radius | string | - | List Item chrome for fill, text, type size, and radius. See List Item. |
| children | ReactNode | - | Footer copy or link label. |
Theme defaults live on :root. Override these globally or on a local host.
| Token | Type | Default | Notes |
|---|---|---|---|
| --df-dropdown-menu-shadow | CSS box-shadow | none | Panel elevation. Off by default. Set by Content or SubContent shadow. |
| --df-dropdown-menu-body-max-height | CSS length | min(60vh, var(--df-menu-max-height)) | Default Body maxHeight when scrollable is true. |
| --df-dropdown-menu-label-size | CSS length | var(--df-text-11) | Default DropdownMenuLabel type size. |
| --df-dropdown-menu-header-avatar-size | CSS length | calc(var(--df-leading-5) + var(--df-dropdown-menu-header-copy-gap) + var(--df-leading-4)) | Avatar size in Header when title and description are both present. |
| --df-dropdown-menu-submenu-open-duration | CSS time | var(--df-duration-slow) | Default submenu open motion. Matches Option List nested open timing. Override with Submenu or SubContent openDuration. |
| --df-dropdown-menu-submenu-close-duration | CSS time | var(--df-duration-fast) | Default submenu close motion. Matches Option List nested close timing. Override with Submenu or SubContent closeDuration. |