Displays a menu to the user—such as a set of actions or functions—triggered by a button.
<DropdownMenu.root id="dropdown-primitive">
<DropdownMenu.trigger
id="dropdown-trigger"
content_id="dropdown-content"
class="DemoIconButton"
aria-label="Customise options"
>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M1.5 3C1.22386 3 1 3.22386 1 3.5C1 3.77614 1.22386 4 1.5 4H13.5C13.7761 4 14 3.77614 14 3.5C14 3.22386 13.7761 3 13.5 3H1.5ZM1 7.5C1 7.22386 1.22386 7 1.5 7H13.5C13.7761 7 14 7.22386 14 7.5C14 7.77614 13.7761 8 13.5 8H1.5C1.22386 8 1 7.77614 1 7.5ZM1 11.5C1 11.2239 1.22386 11 1.5 11H13.5C13.7761 11 14 11.2239 14 11.5C14 11.7761 13.7761 12 13.5 12H1.5C1.22386 12 1 11.7761 1 11.5Z"
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
>
</path>
</svg>
</DropdownMenu.trigger>
<DropdownMenu.content
id="dropdown-content"
class="DemoDropdownMenuContent"
side_offset={5}
>
<DropdownMenu.item
class="DemoDropdownMenuItem"
text_value="New Tab"
>
New Tab
<div class="DemoRightSlot">⌘+T</div>
</DropdownMenu.item>
<DropdownMenu.item
class="DemoDropdownMenuItem"
text_value="New Window"
>
New Window
<div class="DemoRightSlot">⌘+N</div>
</DropdownMenu.item>
<DropdownMenu.item
class="DemoDropdownMenuItem"
disabled
text_value="New Private Window"
>
New Private Window
<div class="DemoRightSlot">⇧+⌘+N</div>
</DropdownMenu.item>
<DropdownMenu.sub>
<DropdownMenu.sub_trigger
class="DemoDropdownMenuSubTrigger"
text_value="More Tools"
>
More Tools
<div class="DemoRightSlot">
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M6.1584 3.13508C6.35985 2.94621 6.67627 2.95642 6.86514 3.15788L10.61514 7.15788C10.7954 7.3502 10.7954 7.64949 10.61514 7.84182L6.86514 11.8418C6.67627 12.0433 6.35985 12.0535 6.1584 11.8646C5.95694 11.6757 5.94673 11.3593 6.1356 11.1579L9.565 7.49985L6.1356 3.84182C5.94673 3.64036 5.95694 3.32394 6.1584 3.13508Z"
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
>
</path>
</svg>
</div>
</DropdownMenu.sub_trigger>
<DropdownMenu.sub_content
class="DemoDropdownMenuSubContent"
side_offset={2}
>
<DropdownMenu.item
class="DemoDropdownMenuItem"
text_value="Save Page As"
>
Save Page As…
<div class="DemoRightSlot">⌘+S</div>
</DropdownMenu.item>
<DropdownMenu.item
class="DemoDropdownMenuItem"
text_value="Create Shortcut"
>
Create Shortcut…
</DropdownMenu.item>
<DropdownMenu.item
class="DemoDropdownMenuItem"
text_value="Name Window"
>
Name Window…
</DropdownMenu.item>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.item
class="DemoDropdownMenuItem"
text_value="Developer Tools"
>
Developer Tools
</DropdownMenu.item>
</DropdownMenu.sub_content>
</DropdownMenu.sub>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.checkbox_item
class="DemoDropdownMenuCheckboxItem"
checked
text_value="Show Bookmarks"
>
<DropdownMenu.item_indicator
class="DemoDropdownMenuItemIndicator"
force_mount
>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z"
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
>
</path>
</svg>
</DropdownMenu.item_indicator>
Show Bookmarks
<div class="DemoRightSlot">⌘+B</div>
</DropdownMenu.checkbox_item>
<DropdownMenu.checkbox_item
class="DemoDropdownMenuCheckboxItem"
text_value="Show Full URLs"
>
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z"
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
>
</path>
</svg>
</DropdownMenu.item_indicator>
Show Full URLs
</DropdownMenu.checkbox_item>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.label class="DemoDropdownMenuLabel">People</DropdownMenu.label>
<DropdownMenu.radio_group value="pedro">
<DropdownMenu.radio_item
class="DemoDropdownMenuRadioItem"
value="pedro"
checked
>
<DropdownMenu.item_indicator
class="DemoDropdownMenuItemIndicator"
force_mount
>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M9.875 7.5C9.875 8.81168 8.81168 9.875 7.5 9.875C6.18832 9.875 5.125 8.81168 5.125 7.5C5.125 6.18832 6.18832 5.125 7.5 5.125C8.81168 5.125 9.875 6.18832 9.875 7.5Z"
fill="currentColor"
>
</path>
</svg>
</DropdownMenu.item_indicator>
Pedro Duarte
</DropdownMenu.radio_item>
<DropdownMenu.radio_item
class="DemoDropdownMenuRadioItem"
value="colm"
>
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M9.875 7.5C9.875 8.81168 8.81168 9.875 7.5 9.875C6.18832 9.875 5.125 8.81168 5.125 7.5C5.125 6.18832 6.18832 5.125 7.5 5.125C8.81168 5.125 9.875 6.18832 9.875 7.5Z"
fill="currentColor"
>
</path>
</svg>
</DropdownMenu.item_indicator>
Colm Tuite
</DropdownMenu.radio_item>
</DropdownMenu.radio_group>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.item
class="DemoDropdownMenuItem"
text_value="Close"
>
Close
</DropdownMenu.item>
<DropdownMenu.arrow class="DemoDropdownMenuArrow" />
</DropdownMenu.content>
</DropdownMenu.root>
/* reset */
button {
all: unset;
}
.DemoDropdownMenuContent,
.DemoDropdownMenuSubContent {
min-width: 220px;
background-color: white;
border-radius: 6px;
padding: 5px;
box-shadow:
0px 10px 38px -10px rgba(22, 23, 24, 0.35),
0px 10px 20px -15px rgba(22, 23, 24, 0.2);
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
will-change: transform, opacity;
}
.DemoDropdownMenuContent[data-side="top"],
.DemoDropdownMenuSubContent[data-side="top"] {
animation-name: slideDownAndFade;
}
.DemoDropdownMenuContent[data-side="right"],
.DemoDropdownMenuSubContent[data-side="right"] {
animation-name: slideLeftAndFade;
}
.DemoDropdownMenuContent[data-side="bottom"],
.DemoDropdownMenuSubContent[data-side="bottom"] {
animation-name: slideUpAndFade;
}
.DemoDropdownMenuContent[data-side="left"],
.DemoDropdownMenuSubContent[data-side="left"] {
animation-name: slideRightAndFade;
}
.DemoDropdownMenuItem,
.DemoDropdownMenuCheckboxItem,
.DemoDropdownMenuRadioItem,
.DemoDropdownMenuSubTrigger {
font-size: 13px;
line-height: 1;
color: var(--violet-11);
border-radius: 3px;
display: flex;
align-items: center;
height: 25px;
padding: 0 5px;
position: relative;
padding-left: 25px;
user-select: none;
outline: none;
}
.DemoDropdownMenuSubTrigger[data-state="open"] {
background-color: var(--violet-4);
color: var(--violet-11);
}
.DemoDropdownMenuItem[data-disabled],
.DemoDropdownMenuCheckboxItem[data-disabled],
.DemoDropdownMenuRadioItem[data-disabled],
.DemoDropdownMenuSubTrigger[data-disabled] {
color: var(--mauve-8);
pointer-events: none;
}
.DemoDropdownMenuItem[data-highlighted],
.DemoDropdownMenuCheckboxItem[data-highlighted],
.DemoDropdownMenuRadioItem[data-highlighted],
.DemoDropdownMenuSubTrigger[data-highlighted] {
background-color: var(--violet-9);
color: var(--violet-1);
}
.DemoDropdownMenuLabel {
padding-left: 25px;
font-size: 12px;
line-height: 25px;
color: var(--mauve-11);
}
.DemoDropdownMenuSeparator {
height: 1px;
background-color: var(--violet-6);
margin: 5px;
}
.DemoDropdownMenuItemIndicator {
position: absolute;
left: 0;
width: 25px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.DemoDropdownMenuArrow {
fill: white;
}
.DemoIconButton {
font-family: inherit;
border-radius: 100%;
height: 35px;
width: 35px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--violet-11);
background-color: white;
box-shadow: 0 2px 10px var(--black-a7);
}
.DemoIconButton:hover {
background-color: var(--violet-3);
}
.DemoIconButton:focus {
box-shadow: 0 0 0 2px black;
}
.DemoRightSlot {
margin-left: auto;
padding-left: 20px;
color: var(--mauve-11);
}
[data-highlighted] > .DemoRightSlot {
color: white;
}
[data-disabled] .DemoRightSlot {
color: var(--mauve-8);
}
@keyframes slideUpAndFade {
from {
opacity: 0;
transform: translateY(2px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideRightAndFade {
from {
opacity: 0;
transform: translateX(-2px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideDownAndFade {
from {
opacity: 0;
transform: translateY(-2px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideLeftAndFade {
from {
opacity: 0;
transform: translateX(2px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
Anatomy
Import all parts and piece them together.
<DropdownMenu.root id="…">
<DropdownMenu.trigger content_id="…" />
<DropdownMenu.portal>
<DropdownMenu.content id="…">
<DropdownMenu.label />
<DropdownMenu.item />
<DropdownMenu.group>
<DropdownMenu.item />
</DropdownMenu.group>
<DropdownMenu.checkbox_item>
<DropdownMenu.item_indicator />
</DropdownMenu.checkbox_item>
<DropdownMenu.radio_group>
<DropdownMenu.radio_item>
<DropdownMenu.item_indicator />
</DropdownMenu.radio_item>
</DropdownMenu.radio_group>
<DropdownMenu.sub>
<DropdownMenu.sub_trigger />
<DropdownMenu.sub_content />
</DropdownMenu.sub>
<DropdownMenu.separator />
<DropdownMenu.arrow />
</DropdownMenu.content>
</DropdownMenu.portal>
</DropdownMenu.root>
Anatomy
-
Root - Contains all the parts of a dropdown menu.
-
Trigger - The button that toggles the dropdown menu.
-
Portal - Portals the content into the document (default `body`).
-
Content - The component that pops out when the menu is open.
-
Item - An actionable menu item.
-
Checkbox Item - An item that can be checked or unchecked.
-
Radio Group - Groups mutually exclusive `radio_item` parts.
-
Radio Item - An item that can be selected among a radio group.
-
Item Indicator - Renders when a checkbox or radio item is checked.
-
Label - A non-focusable section label.
-
Separator - Visually separates groups of items.
-
Group - Groups multiple items.
-
Arrow - Optional pointer linking the trigger to the content.
-
Sub - Contains all the parts of a submenu.
-
Sub Trigger - An item that opens a submenu.
-
Sub Content - The submenu panel.
API Reference
Root
Contains all the parts of a dropdown menu.
| Prop | Type | Default | Description |
|---|---|---|---|
default_open
|
boolean
|
false
|
|
dir
|
string
|
"ltr"
|
|
id
|
string
|
—
|
|
modal
|
boolean
|
true
|
|
on_open_change
|
string
|
nil
|
|
open
|
boolean
|
false
|
default_open
boolean
Default
false
dir
string
Default
"ltr"
id
string
Default
—
modal
boolean
Default
true
on_open_change
string
Default
nil
open
boolean
Default
false
Trigger
The button that toggles the dropdown menu. By default, DropdownMenu.content positions itself against the trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
as
|
string
|
"button"
|
|
content_id
|
string
|
nil
|
|
disabled
|
boolean
|
false
|
|
id
|
string
|
nil
|
as
string
Default
"button"
content_id
string
Default
nil
disabled
boolean
Default
false
id
string
Default
nil
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
open | closed
|
Reflects whether the menu is open. |
[data-disabled]
|
Present when disabled
|
Present when the trigger is disabled. |
Portal
When used, portals the content part into the target (default body).
| Prop | Type | Default | Description |
|---|---|---|---|
class
|
any
|
nil
|
|
container
|
string
|
"div"
|
|
id
|
string
|
—
|
|
target
|
string
|
"body"
|
class
any
Default
nil
container
string
Default
"div"
id
string
Default
—
target
string
Default
"body"
Content
The component that pops out when the dropdown menu is open.
| Prop | Type | Default | Description |
|---|---|---|---|
align
|
string
|
"start"
|
|
id
|
string
|
nil
|
|
loop
|
boolean
|
true
|
|
side
|
string
|
"bottom"
|
|
side_offset
|
integer
|
4
|
align
string
Default
"start"
id
string
Default
nil
loop
boolean
Default
true
side
string
Default
"bottom"
side_offset
integer
Default
4
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
open | closed
|
Reflects whether the menu is open. |
[data-side]
|
left | right | bottom | top
|
The side of the trigger the content rendered against. |
[data-align]
|
start | end | center
|
The alignment against the trigger. |
[data-orientation]
|
vertical | horizontal
|
The orientation of the menu. |
| CSS variable | Description |
| --- | --- |
| --radix-dropdown-menu-content-transform-origin | The transform-origin computed from content and arrow positions/offsets |
| --radix-dropdown-menu-content-available-width | Remaining width between the trigger and the boundary edge |
| --radix-dropdown-menu-content-available-height | Remaining height between the trigger and the boundary edge |
| --radix-dropdown-menu-trigger-width | The width of the trigger |
| --radix-dropdown-menu-trigger-height | The height of the trigger |
Item
The component that contains the dropdown menu items.
| Prop | Type | Default | Description |
|---|---|---|---|
disabled
|
boolean
|
false
|
|
id
|
string
|
nil
|
|
text_value
|
string
|
nil
|
disabled
boolean
Default
false
id
string
Default
nil
text_value
string
Default
nil
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-orientation]
|
vertical | horizontal
|
The orientation of the menu. |
[data-highlighted]
|
Present when highlighted
|
Present when the item is highlighted. |
[data-disabled]
|
Present when disabled
|
Present when the item is disabled. |
Checkbox Item
An item that can be controlled and rendered like a checkbox.
| Prop | Type | Default | Description |
|---|---|---|---|
checked
|
boolean
|
false
|
|
disabled
|
boolean
|
false
|
|
id
|
string
|
nil
|
|
text_value
|
string
|
nil
|
checked
boolean
Default
false
disabled
boolean
Default
false
id
string
Default
nil
text_value
string
Default
nil
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
checked | unchecked
|
Reflects the checked state. |
[data-highlighted]
|
Present when highlighted
|
Present when the item is highlighted. |
[data-disabled]
|
Present when disabled
|
Present when the item is disabled. |
Radio Group
Used to group multiple DropdownMenu.radio_item parts.
| Prop | Type | Default | Description |
|---|---|---|---|
id
|
string
|
nil
|
|
value
|
string
|
nil
|
id
string
Default
nil
value
string
Default
nil
Radio Item
An item that can be controlled and rendered like a radio.
| Prop | Type | Default | Description |
|---|---|---|---|
checked
|
boolean
|
false
|
|
disabled
|
boolean
|
false
|
|
id
|
string
|
nil
|
|
text_value
|
string
|
nil
|
|
value
|
string
|
—
|
checked
boolean
Default
false
disabled
boolean
Default
false
id
string
Default
nil
text_value
string
Default
nil
value
string
Default
—
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
checked | unchecked
|
Reflects the selected state. |
[data-highlighted]
|
Present when highlighted
|
Present when the item is highlighted. |
[data-disabled]
|
Present when disabled
|
Present when the item is disabled. |
Item Indicator
Renders when the parent checkbox_item or radio_item is checked. Style directly or wrap an icon.
| Prop | Type | Default | Description |
|---|---|---|---|
force_mount
|
boolean
|
false
|
|
id
|
string
|
nil
|
force_mount
boolean
Default
false
id
string
Default
nil
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
checked | unchecked
|
Reflects the checked state of the parent item. |
Label
Used to render a label. It won't be focusable using arrow keys.
| Prop | Type | Default | Description |
|---|---|---|---|
id
|
string
|
nil
|
id
string
Default
nil
Separator
Used to visually separate items in the dropdown menu.
| Prop | Type | Default | Description |
|---|---|---|---|
decorative
|
boolean
|
true
|
|
id
|
string
|
nil
|
decorative
boolean
Default
true
id
string
Default
nil
Group
Used to group multiple DropdownMenu.item parts.
| Prop | Type | Default | Description |
|---|---|---|---|
id
|
string
|
nil
|
id
string
Default
nil
Arrow
An optional arrow element rendered alongside the content to visually link the trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
id
|
string
|
nil
|
id
string
Default
nil
Sub
Contains all the parts of a submenu.
| Prop | Type | Default | Description |
|---|---|---|---|
id
|
string
|
nil
|
|
open
|
boolean
|
false
|
id
string
Default
nil
open
boolean
Default
false
Sub Trigger
An item that opens a submenu. Must be rendered inside DropdownMenu.sub.
| Prop | Type | Default | Description |
|---|---|---|---|
disabled
|
boolean
|
false
|
|
id
|
string
|
nil
|
|
text_value
|
string
|
nil
|
disabled
boolean
Default
false
id
string
Default
nil
text_value
string
Default
nil
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
open | closed
|
Reflects whether the submenu is open. |
[data-highlighted]
|
Present when highlighted
|
Present when the item is highlighted. |
[data-disabled]
|
Present when disabled
|
Present when the item is disabled. |
Sub Content
The component that pops out when a submenu is open. Must be rendered inside DropdownMenu.sub.
| Prop | Type | Default | Description |
|---|---|---|---|
align
|
string
|
"start"
|
|
id
|
string
|
nil
|
|
side
|
string
|
"right"
|
|
side_offset
|
integer
|
0
|
align
string
Default
"start"
id
string
Default
nil
side
string
Default
"right"
side_offset
integer
Default
0
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
open | closed
|
Reflects whether the submenu is open. |
[data-side]
|
left | right | bottom | top
|
The side the submenu rendered against. |
[data-align]
|
start | end | center
|
The alignment of the submenu. |
[data-orientation]
|
vertical | horizontal
|
The orientation of the submenu. |
Examples
With submenus
You can create submenus by using DropdownMenu.sub in combination with its parts.
<DropdownMenu.root id="dropdown-sub">
<DropdownMenu.trigger id="dropdown-sub-trigger" content_id="dropdown-sub-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-sub-content">
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.sub>
<DropdownMenu.sub_trigger class="DemoDropdownMenuSubTrigger">Sub menu →</DropdownMenu.sub_trigger>
<DropdownMenu.sub_content class="DemoDropdownMenuSubContent">
<DropdownMenu.item class="DemoDropdownMenuItem">Sub menu item</DropdownMenu.item>
<DropdownMenu.item class="DemoDropdownMenuItem">Sub menu item</DropdownMenu.item>
<DropdownMenu.arrow class="DemoDropdownMenuArrow" />
</DropdownMenu.sub_content>
</DropdownMenu.sub>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
</DropdownMenu.content>
</DropdownMenu.root>
With disabled items
You can add special styles to disabled items via the data-disabled attribute.
<DropdownMenu.root id="dropdown-disabled">
<DropdownMenu.trigger id="dropdown-disabled-trigger" content_id="dropdown-disabled-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-disabled-content">
<DropdownMenu.item class="DemoDropdownMenuItem" disabled>…</DropdownMenu.item>
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
</DropdownMenu.content>
</DropdownMenu.root>
.DemoDropdownMenuItem[data-disabled] {
color: gainsboro;
}
With separators
Use the separator part to add a separator between items.
<DropdownMenu.root id="dropdown-separators">
<DropdownMenu.trigger id="dropdown-separators-trigger" content_id="dropdown-separators-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-separators-content">
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
</DropdownMenu.content>
</DropdownMenu.root>
With labels
Use the label part to help label a section.
<DropdownMenu.root id="dropdown-labels">
<DropdownMenu.trigger id="dropdown-labels-trigger" content_id="dropdown-labels-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-labels-content">
<DropdownMenu.label class="DemoDropdownMenuLabel">Label</DropdownMenu.label>
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
</DropdownMenu.content>
</DropdownMenu.root>
With checkbox items
Use the checkbox_item part to add an item that can be checked. Pass checked from LiveView assigns to control state.
<DropdownMenu.root id="dropdown-checkbox">
<DropdownMenu.trigger id="dropdown-checkbox-trigger" content_id="dropdown-checkbox-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-checkbox-content">
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.item class="DemoDropdownMenuItem">…</DropdownMenu.item>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.checkbox_item checked={@checked} class="DemoDropdownMenuCheckboxItem" text_value="Checkbox item">
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">✓</DropdownMenu.item_indicator>
Checkbox item
</DropdownMenu.checkbox_item>
</DropdownMenu.content>
</DropdownMenu.root>
With radio items
Use the radio_group and radio_item parts to add an item that can be checked amongst others.
<DropdownMenu.root id="dropdown-radio">
<DropdownMenu.trigger id="dropdown-radio-trigger" content_id="dropdown-radio-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-radio-content">
<DropdownMenu.radio_group value={@color}>
<DropdownMenu.radio_item value="red" checked={@color == "red"} class="DemoDropdownMenuRadioItem">
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">●</DropdownMenu.item_indicator>
Red
</DropdownMenu.radio_item>
<DropdownMenu.radio_item value="blue" checked={@color == "blue"} class="DemoDropdownMenuRadioItem">
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">●</DropdownMenu.item_indicator>
Blue
</DropdownMenu.radio_item>
<DropdownMenu.radio_item value="green" checked={@color == "green"} class="DemoDropdownMenuRadioItem">
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">●</DropdownMenu.item_indicator>
Green
</DropdownMenu.radio_item>
</DropdownMenu.radio_group>
</DropdownMenu.content>
</DropdownMenu.root>
With complex items
You can add extra decorative elements in the item parts, such as images.
<DropdownMenu.root id="dropdown-complex">
<DropdownMenu.trigger id="dropdown-complex-trigger" content_id="dropdown-complex-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-complex-content">
<DropdownMenu.item class="DemoDropdownMenuItem">
<img src="…" alt="" />
Adolfo Hess
</DropdownMenu.item>
<DropdownMenu.item class="DemoDropdownMenuItem">
<img src="…" alt="" />
Miyah Myles
</DropdownMenu.item>
</DropdownMenu.content>
</DropdownMenu.root>
Constrain the content/sub-content size
You may want to constrain the width of the content (or sub-content) so that it matches the trigger width, or constrain its height to not exceed the viewport.
We expose several CSS custom properties such as --radix-dropdown-menu-trigger-width and --radix-dropdown-menu-content-available-height to support this. Use them to constrain the content dimensions.
<DropdownMenu.root id="dropdown-constrain">
<DropdownMenu.trigger id="dropdown-constrain-trigger" content_id="dropdown-constrain-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-constrain-content" class="DemoDropdownMenuContent" side_offset={5}>
…
</DropdownMenu.content>
</DropdownMenu.root>
.DemoDropdownMenuContent {
width: var(--radix-dropdown-menu-trigger-width);
max-height: var(--radix-dropdown-menu-content-available-height);
}
Origin-aware animations
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, side_offset, align, and any collisions.
<DropdownMenu.root id="dropdown-origin">
<DropdownMenu.trigger id="dropdown-origin-trigger" content_id="dropdown-origin-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-origin-content" class="DemoDropdownMenuContent">
…
</DropdownMenu.content>
</DropdownMenu.root>
.DemoDropdownMenuContent {
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);
}
}
Collision-aware animations
We expose data-side and data-align attributes. Their values change at runtime to reflect collisions. Use them to create collision and direction-aware animations.
<DropdownMenu.root id="dropdown-collision">
<DropdownMenu.trigger id="dropdown-collision-trigger" content_id="dropdown-collision-content">…</DropdownMenu.trigger>
<DropdownMenu.content id="dropdown-collision-content" class="DemoDropdownMenuContent">
…
</DropdownMenu.content>
</DropdownMenu.root>
.DemoDropdownMenuContent {
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.DemoDropdownMenuContent[data-side="top"] {
animation-name: slideUp;
}
.DemoDropdownMenuContent[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);
}
}
Accessibility
Adheres to the Menu Button WAI-ARIA design pattern and uses roving tabindex to manage focus movement among menu items.
Keyboard Interactions
Keyboard Interactions
| 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. |
ArrowRight, ArrowLeft
|
When focus is on `DropdownMenu.sub_trigger`, opens or closes the submenu depending on reading direction. |
Esc
|
Closes the dropdown menu and moves focus to `DropdownMenu.trigger`. |
Custom APIs
Create your own API by abstracting the primitive parts into your own component.
Abstract the arrow and item indicators
This example abstracts DropdownMenu.arrow and DropdownMenu.item_indicator. It also wraps implementation details for checkbox_item and radio_item.
Usage
<.dropdown_menu id="my-menu">
<:trigger>DropdownMenu trigger</:trigger>
<:content>
<DropdownMenu.item class="DemoDropdownMenuItem">Item</DropdownMenu.item>
<DropdownMenu.label class="DemoDropdownMenuLabel">Label</DropdownMenu.label>
<.dropdown_menu_checkbox_item checked={@checked}>Checkbox item</.dropdown_menu_checkbox_item>
<DropdownMenu.separator class="DemoDropdownMenuSeparator" />
<DropdownMenu.radio_group value={@color}>
<.dropdown_menu_radio_item value="a" checked={@color == "a"}>Radio A</.dropdown_menu_radio_item>
<.dropdown_menu_radio_item value="b" checked={@color == "b"}>Radio B</.dropdown_menu_radio_item>
</DropdownMenu.radio_group>
</:content>
</.dropdown_menu>
Implementation
def dropdown_menu(assigns) do
~H"""
<DropdownMenu.root id={@id}>
<DropdownMenu.trigger id={"#{@id}-trigger"} content_id={"#{@id}-content"}>
{render_slot(@trigger)}
</DropdownMenu.trigger>
<DropdownMenu.content id={"#{@id}-content"} class="DemoDropdownMenuContent">
{render_slot(@content)}
<DropdownMenu.arrow class="DemoDropdownMenuArrow" />
</DropdownMenu.content>
</DropdownMenu.root>
"""
end
def dropdown_menu_checkbox_item(assigns) do
~H"""
<DropdownMenu.checkbox_item checked={@checked} class="DemoDropdownMenuCheckboxItem" {@rest}>
{render_slot(@inner_block)}
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">✓</DropdownMenu.item_indicator>
</DropdownMenu.checkbox_item>
"""
end
def dropdown_menu_radio_item(assigns) do
~H"""
<DropdownMenu.radio_item value={@value} checked={@checked} class="DemoDropdownMenuRadioItem" {@rest}>
{render_slot(@inner_block)}
<DropdownMenu.item_indicator class="DemoDropdownMenuItemIndicator">●</DropdownMenu.item_indicator>
</DropdownMenu.radio_item>
"""
end