Displays a menu to the user—such as a set of actions or functions—triggered by a button.
import React from 'react';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import {
HamburgerMenuIcon,
DotFilledIcon,
CheckIcon,
ChevronRightIcon,
} from '@radix-ui/react-icons';
import './styles.css';
const DropdownMenuDemo = () => {
const [bookmarksChecked, setBookmarksChecked] = React.useState(true);
const [urlsChecked, setUrlsChecked] = React.useState(false);
const [person, setPerson] = React.useState('pedro');
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<button className="IconButton" aria-label="Customise options">
<HamburgerMenuIcon />
</button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content className="DropdownMenuContent" sideOffset={5}>
<DropdownMenu.Item className="DropdownMenuItem">
New Tab <div className="RightSlot">⌘+T</div>
</DropdownMenu.Item>
<DropdownMenu.Item className="DropdownMenuItem">
New Window <div className="RightSlot">⌘+N</div>
</DropdownMenu.Item>
<DropdownMenu.Item className="DropdownMenuItem" disabled>
New Private Window <div className="RightSlot">⇧+⌘+N</div>
</DropdownMenu.Item>
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger className="DropdownMenuSubTrigger">
More Tools
<div className="RightSlot">
<ChevronRightIcon />
</div>
</DropdownMenu.SubTrigger>
<DropdownMenu.Portal>
<DropdownMenu.SubContent
className="DropdownMenuSubContent"
sideOffset={2}
alignOffset={-5}
>
<DropdownMenu.Item className="DropdownMenuItem">
Save Page As… <div className="RightSlot">⌘+S</div>
</DropdownMenu.Item>
<DropdownMenu.Item className="DropdownMenuItem">Create Shortcut…</DropdownMenu.Item>
<DropdownMenu.Item className="DropdownMenuItem">Name Window…</DropdownMenu.Item>
<DropdownMenu.Separator className="DropdownMenu.Separator" />
<DropdownMenu.Item className="DropdownMenuItem">Developer Tools</DropdownMenu.Item>
</DropdownMenu.SubContent>
</DropdownMenu.Portal>
</DropdownMenu.Sub>
<DropdownMenu.Separator className="DropdownMenuSeparator" />
<DropdownMenu.CheckboxItem
className="DropdownMenuCheckboxItem"
checked={bookmarksChecked}
onCheckedChange={setBookmarksChecked}
>
<DropdownMenu.ItemIndicator className="DropdownMenuItemIndicator">
<CheckIcon />
</DropdownMenu.ItemIndicator>
Show Bookmarks <div className="RightSlot">⌘+B</div>
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
className="DropdownMenuCheckboxItem"
checked={urlsChecked}
onCheckedChange={setUrlsChecked}
>
<DropdownMenu.ItemIndicator className="DropdownMenuItemIndicator">
<CheckIcon />
</DropdownMenu.ItemIndicator>
Show Full URLs
</DropdownMenu.CheckboxItem>
<DropdownMenu.Separator className="DropdownMenuSeparator" />
<DropdownMenu.Label className="DropdownMenuLabel">People</DropdownMenu.Label>
<DropdownMenu.RadioGroup value={person} onValueChange={setPerson}>
<DropdownMenu.RadioItem className="DropdownMenuRadioItem" value="pedro">
<DropdownMenu.ItemIndicator className="DropdownMenuItemIndicator">
<DotFilledIcon />
</DropdownMenu.ItemIndicator>
Pedro Duarte
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem className="DropdownMenuRadioItem" value="colm">
<DropdownMenu.ItemIndicator className="DropdownMenuItemIndicator">
<DotFilledIcon />
</DropdownMenu.ItemIndicator>
Colm Tuite
</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
<DropdownMenu.Arrow className="DropdownMenuArrow" />
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
};
export default DropdownMenuDemo;
Install the component from your command line.
npm install @radix-ui/react-dropdown-menu
Import all parts and piece them together.
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
export default () => (
<DropdownMenu.Root>
<DropdownMenu.Trigger />
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Label />
<DropdownMenu.Item />
<DropdownMenu.Group>
<DropdownMenu.Item />
</DropdownMenu.Group>
<DropdownMenu.CheckboxItem>
<DropdownMenu.ItemIndicator />
</DropdownMenu.CheckboxItem>
<DropdownMenu.RadioGroup>
<DropdownMenu.RadioItem>
<DropdownMenu.ItemIndicator />
</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger />
<DropdownMenu.Portal>
<DropdownMenu.SubContent />
</DropdownMenu.Portal>
</DropdownMenu.Sub>
<DropdownMenu.Separator />
<DropdownMenu.Arrow />
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
Contains all the parts of a dropdown menu.
Prop | Type | Default |
---|---|---|
defaultOpen | boolean | |
open | boolean | |
onOpenChange | function | |
modal | boolean | true |
dir | enum |
The button that toggles the dropdown menu. By default, the DropdownMenu.Content
will position itself against the trigger.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
Data Attribute | Values |
---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
When used, portals the content part into the body
.
Prop | Type | Default |
---|---|---|
forceMount | boolean | |
container | HTMLElement | document.body |
The component that pops out when the dropdown menu is open.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
loop | boolean | false |
onCloseAutoFocus | function | |
onEscapeKeyDown | function | |
onPointerDownOutside | function | |
onFocusOutside | function | |
onInteractOutside | function | |
forceMount | boolean | |
side | enum | "bottom" |
sideOffset | number | 0 |
align | enum | "center" |
alignOffset | number | 0 |
avoidCollisions | boolean | true |
collisionBoundary | Boundary | [] |
collisionPadding | number | Padding | 0 |
arrowPadding | number | 0 |
sticky | enum | "partial" |
hideWhenDetached | boolean | false |
Data Attribute | Values |
---|---|
[data-state] | "open" | "closed" |
[data-side] | "left" | "right" | "bottom" | "top" |
[data-align] | "start" | "end" | "center" |
[data-orientation] | "vertical" | "horizontal" |
CSS Variable | Description |
---|---|
--radix-dropdown-menu-content-transform-origin | The transform-origin computed from the content and arrow positions/offsets |
An optional arrow element to render alongside the dropdown menu. This can be used to help visually link the trigger with the DropdownMenu.Content
. Must be rendered inside DropdownMenu.Content
.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
width | number | 10 |
height | number | 5 |
The component that contains the dropdown menu items.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
disabled | boolean | |
onSelect | function | |
textValue | string |
Data Attribute | Values |
---|---|
[data-orientation] | "vertical" | "horizontal" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
Used to group multiple DropdownMenu.Item
s.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
Used to render a label. It won't be focusable using arrow keys.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
An item that can be controlled and rendered like a checkbox.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
checked | boolean | 'indeterminate' | |
onCheckedChange | function | |
disabled | boolean | |
onSelect | function | |
textValue | string |
Data Attribute | Values |
---|---|
[data-state] | "checked" | "unchecked" | "indeterminate" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
Used to group multiple DropdownMenu.RadioItem
s.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
value | string | |
onValueChange | function |
An item that can be controlled and rendered like a radio.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
value* | string | |
disabled | boolean | |
onSelect | function | |
textValue | string |
Data Attribute | Values |
---|---|
[data-state] | "checked" | "unchecked" | "indeterminate" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
Renders when the parent DropdownMenu.CheckboxItem
or DropdownMenu.RadioItem
is checked. You can style this element directly, or you can use it as a wrapper to put an icon into, or both.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
forceMount | boolean |
Data Attribute | Values |
---|---|
[data-state] | "checked" | "unchecked" | "indeterminate" |
Used to visually separate items in the dropdown menu.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
Contains all the parts of a submenu.
Prop | Type | Default |
---|---|---|
defaultOpen | boolean | |
open | boolean | |
onOpenChange | function |
An item that opens a submenu. Must be rendered inside DropdownMenu.Sub
.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
disabled | boolean | |
textValue | string |
Data Attribute | Values |
---|---|
[data-state] | "open" | "closed" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
The component that pops out when a submenu is open. Must be rendered inside DropdownMenu.Sub
.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
loop | boolean | false |
onEscapeKeyDown | function | |
onPointerDownOutside | function | |
onFocusOutside | function | |
onInteractOutside | function | |
forceMount | boolean | |
sideOffset | number | 0 |
alignOffset | number | 0 |
avoidCollisions | boolean | true |
collisionBoundary | Boundary | [] |
collisionPadding | number | Padding | 0 |
arrowPadding | number | 0 |
sticky | enum | "partial" |
hideWhenDetached | boolean | false |
Data Attribute | Values |
---|---|
[data-state] | "open" | "closed" |
[data-side] | "left" | "right" | "bottom" | "top" |
[data-align] | "start" | "end" | "center" |
[data-orientation] | "vertical" | "horizontal" |
You can create submenus by using DropdownMenu.Sub
in combination with its parts.
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger>Sub menu →</DropdownMenu.SubTrigger>
<DropdownMenu.Portal>
<DropdownMenu.SubContent>
<DropdownMenu.Item>Sub menu item</DropdownMenu.Item>
<DropdownMenu.Item>Sub menu item</DropdownMenu.Item>
<DropdownMenu.Arrow />
</DropdownMenu.SubContent>
</DropdownMenu.Portal>
</DropdownMenu.Sub>
<DropdownMenu.Separator />
<DropdownMenu.Item>…</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
You can add special styles to disabled items via the data-disabled
attribute.
// index.jsx
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import './styles.css';
export default () => (
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Item className="DropdownMenuItem" disabled>
…
</DropdownMenu.Item>
<DropdownMenu.Item className="DropdownMenuItem">…</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
/* styles.css */
.DropdownMenuItem[data-disabled] {
color: gainsboro;
}
Use the Separator
part to add a separator between items.
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item>…</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
Use the Label
part to help label a section.
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Label>Label</DropdownMenu.Label>
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Item>…</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
Use the CheckboxItem
part to add an item that can be checked.
import React from 'react';
import { CheckIcon } from '@radix-ui/react-icons';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
export default () => {
const [checked, setChecked] = React.useState(true);
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Item>…</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.CheckboxItem
checked={checked}
onCheckedChange={setChecked}
>
<DropdownMenu.ItemIndicator>
<CheckIcon />
</DropdownMenu.ItemIndicator>
Checkbox item
</DropdownMenu.CheckboxItem>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
};
Use the RadioGroup
and RadioItem
parts to add an item that can be checked amongst others.
import React from 'react';
import { CheckIcon } from '@radix-ui/react-icons';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
export default () => {
const [color, setColor] = React.useState('blue');
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.RadioGroup value={color} onValueChange={setColor}>
<DropdownMenu.RadioItem value="red">
<DropdownMenu.ItemIndicator>
<CheckIcon />
</DropdownMenu.ItemIndicator>
Red
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="blue">
<DropdownMenu.ItemIndicator>
<CheckIcon />
</DropdownMenu.ItemIndicator>
Blue
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="green">
<DropdownMenu.ItemIndicator>
<CheckIcon />
</DropdownMenu.ItemIndicator>
Green
</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
};
You can add extra decorative elements in the Item
parts, such as images.
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
export default () => (
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Item>
<img src="…" />
Adolfo Hess
</DropdownMenu.Item>
<DropdownMenu.Item>
<img src="…" />
Miyah Myles
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
We expose a CSS custom property --radix-dropdown-menu-content-transform-origin
. Use it to animate the content from its computed origin based on side
, sideOffset
, align
, alignOffset
and any collisions.
// index.jsx
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import './styles.css';
export default () => (
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content className="DropdownMenuContent">
…
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
/* styles.css */
.DropdownMenuContent {
transform-origin: var(--radix-dropdown-menu-content-transform-origin);
animation: scaleIn 0.5s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}
We expose data-side
and data-align
attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations.
// index.jsx
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import './styles.css';
export default () => (
<DropdownMenu.Root>
<DropdownMenu.Trigger>…</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content className="DropdownMenuContent">
…
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
/* styles.css */
.DropdownMenuContent {
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.DropdownMenuContent[data-side='top'] {
animation-name: slideUp;
}
.DropdownMenuContent[data-side='bottom'] {
animation-name: slideDown;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Adheres to the Menu Button WAI-ARIA design pattern and uses roving tabindex to manage focus movement among menu items.
Key | Description |
---|---|
Space | When focus is on DropdownMenu.Trigger , opens the dropdown menu and focuses the first item.When focus is on an item, activates the focused item. |
Enter | When focus is on DropdownMenu.Trigger , opens the dropdown menu and focuses the first item.When focus is on an item, activates the focused item. |
ArrowDown | When focus is on DropdownMenu.Trigger , opens the dropdown menu.When focus is on an item, moves focus to the next item. |
ArrowUp | When focus is on an item, moves focus to the previous item. |
ArrowRightArrowLeft | When focus is on DropdownMenu.SubTrigger , opens or closes the submenu depending on reading direction. |
Esc | Closes the dropdown menu and moves focus to DropdownMenu.Trigger . |
Create your own API by abstracting the primitive parts into your own component.
This example abstracts the DropdownMenu.Arrow
and DropdownMenu.ItemIndicator
parts. It also wraps implementation details for CheckboxItem
and RadioItem
.
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuItem,
DropdownMenuGroup,
DropdownMenuCheckboxItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
} from './your-dropdown-menu';
export default () => (
<DropdownMenu>
<DropdownMenuTrigger>DropdownMenu trigger</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Item</DropdownMenuItem>
<DropdownMenuLabel>Label</DropdownMenuLabel>
<DropdownMenuGroup>Group</DropdownMenuGroup>
<DropdownMenuCheckboxItem>CheckboxItem</DropdownMenuCheckboxItem>
<DropdownMenuSeparator>Separator</DropdownMenuSeparator>
<DropdownMenuRadioGroup>
<DropdownMenuRadioItem>RadioItem</DropdownMenuRadioItem>
<DropdownMenuRadioItem>RadioItem</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
);
// your-dropdown-menu.jsx
import React from 'react';
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import { CheckIcon, DividerHorizontalIcon } from '@radix-ui/react-icons';
export const DropdownMenu = DropdownMenuPrimitive.Root;
export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
export const DropdownMenuContent = React.forwardRef(
({ children, ...props }, forwardedRef) => {
return (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content {...props} ref={forwardedRef}>
{children}
<DropdownMenuPrimitive.Arrow />
</DropdownMenuPrimitive.Content>
</DropdownMenuPrimitive.Portal>
);
}
);
export const DropdownMenuLabel = DropdownMenuPrimitive.Label;
export const DropdownMenuItem = DropdownMenuPrimitive.Item;
export const DropdownMenuGroup = DropdownMenuPrimitive.Group;
export const DropdownMenuCheckboxItem = React.forwardRef(
({ children, ...props }, forwardedRef) => {
return (
<DropdownMenuPrimitive.CheckboxItem {...props} ref={forwardedRef}>
{children}
<DropdownMenuPrimitive.ItemIndicator>
{props.checked === 'indeterminate' && <DividerHorizontalIcon />}
{props.checked === true && <CheckIcon />}
</DropdownMenuPrimitive.ItemIndicator>
</DropdownMenuPrimitive.CheckboxItem>
);
}
);
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
export const DropdownMenuRadioItem = React.forwardRef(
({ children, ...props }, forwardedRef) => {
return (
<DropdownMenuPrimitive.RadioItem {...props} ref={forwardedRef}>
{children}
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon />
</DropdownMenuPrimitive.ItemIndicator>
</DropdownMenuPrimitive.RadioItem>
);
}
);
export const DropdownMenuSeparator = DropdownMenuPrimitive.Separator;