Kobalte.v0.12.1

Dropdown Menu

Displays a menu to the user —such as a set of actions or functions— triggered by a button.

Import

ts
import { DropdownMenu } from "@kobalte/core";
ts
import { DropdownMenu } from "@kobalte/core";

Features

  • Exposed to assistive technology as a button with a menu using the WAI ARIA Menu Button design pattern.
  • Supports modal and non-modal modes.
  • Supports submenus.
  • Supports items, labels, groups of items.
  • Supports checkable items (single or multiple) with optional indeterminate state.
  • Support disabled items.
  • Complex item labeling support for accessibility.
  • Keyboard opening and navigation support.
  • Automatic scrolling support during keyboard navigation.
  • Typeahead to allow focusing items by typing text.
  • Optionally render a pointing arrow.
  • Focus is fully managed.
  • Can be controlled or uncontrolled.

Anatomy

The dropdown menu consists of:

  • DropdownMenu.Root: The root container for a dropdown menu.
  • DropdownMenu.Trigger: The button that toggles the menu.
  • DropdownMenu.Icon: A small icon often displayed next to the menu trigger as a visual affordance for the fact it can be open.
  • DropdownMenu.Portal: Portals its children into the body when the menu is open.
  • DropdownMenu.Content: Contains the content to be rendered when the menu is open.
  • DropdownMenu.Arrow: An optional arrow element to render alongside the menu content.
  • DropdownMenu.Separator: Used to visually separate items in the menu.
  • DropdownMenu.Group: Used to group multiple items. Use in conjunction with DropdownMenu.GroupLabel to ensure good accessibility via automatic labelling.
  • DropdownMenu.GroupLabel: Used to render the label of a group. It won't be focusable using arrow keys.
  • DropdownMenu.Sub: Contains all the parts of a submenu.
  • DropdownMenu.SubTrigger: An item that opens a submenu. Must be rendered inside DropdownMenu.Sub.
  • DropdownMenu.SubContent: The component that pops out when a submenu is open. Must be rendered inside DropdownMenu.Sub.

The menu item consists of:

  • DropdownMenu.Item: An item of the select.
  • DropdownMenu.ItemLabel: An accessible label to be announced for the item.
  • DropdownMenu.ItemDescription: An optional accessible description to be announced for the item.
  • DropdownMenu.ItemIndicator: The visual indicator rendered when the item is checked.

The checkable menu item consists of:

  • DropdownMenu.RadioGroup: Used to group multiple DropdownMenu.RadioItems and manage the selection.
  • DropdownMenu.RadioItem: An item that can be controlled and rendered like a radio.
  • DropdownMenu.CheckboxItem: An item that can be controlled and rendered like a checkbox.
tsx
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<DropdownMenu.Icon />
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Arrow />
<DropdownMenu.Item>
<DropdownMenu.ItemLabel />
<DropdownMenu.ItemDescription />
</DropdownMenu.Item>
<DropdownMenu.Group>
<DropdownMenu.GroupLabel />
<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.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
tsx
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<DropdownMenu.Icon />
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>
<DropdownMenu.Arrow />
<DropdownMenu.Item>
<DropdownMenu.ItemLabel />
<DropdownMenu.ItemDescription />
</DropdownMenu.Item>
<DropdownMenu.Group>
<DropdownMenu.GroupLabel />
<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.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>

Example

Usage

Default open

An initial, uncontrolled open value can be provided using the defaultOpen prop.

tsx
<DropdownMenu.Root defaultOpen>...</DropdownMenu.Root>
tsx
<DropdownMenu.Root defaultOpen>...</DropdownMenu.Root>

Controlled open

The open prop can be used to make the open state controlled. The onOpenChange event is fired when the user presses the trigger, an item or interact outside, and receives the new value.

tsx
import { createSignal } from "solid-js";
function ControlledExample() {
const [open, setOpen] = createSignal(false);
return (
<DropdownMenu.Root open={open()} onOpenChange={setOpen}>
<DropdownMenu.Trigger>{open() ? "Close" : "Open"}</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>...</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
}
tsx
import { createSignal } from "solid-js";
function ControlledExample() {
const [open, setOpen] = createSignal(false);
return (
<DropdownMenu.Root open={open()} onOpenChange={setOpen}>
<DropdownMenu.Trigger>{open() ? "Close" : "Open"}</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content>...</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
}

Origin-aware animations

We expose a CSS custom property --kb-menu-content-transform-origin which can be used to animate the content from its computed origin.

css
/* style.css */
.dropdown-menu__content,
.dropdown-menu__sub-content {
transform-origin: var(--kb-menu-content-transform-origin);
animation: contentHide 250ms ease-in forwards;
}
.dropdown-menu__content[data-expanded],
.dropdown-menu__sub-content[data-expanded] {
animation: contentShow 250ms ease-out;
}
@keyframes contentShow {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes contentHide {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.96);
}
}
css
/* style.css */
.dropdown-menu__content,
.dropdown-menu__sub-content {
transform-origin: var(--kb-menu-content-transform-origin);
animation: contentHide 250ms ease-in forwards;
}
.dropdown-menu__content[data-expanded],
.dropdown-menu__sub-content[data-expanded] {
animation: contentShow 250ms ease-out;
}
@keyframes contentShow {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes contentHide {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.96);
}
}

API Reference

PropDescription
openboolean
The controlled open state of the menu.
defaultOpenboolean
The default open state when initially rendered. Useful when you do not need to control the open state.
onOpenChange(open: boolean) => void
Event handler called when the open state of the menu changes.
idstring
A unique identifier for the component. The id is used to generate id attributes for nested components. If no id prop is provided, a generated id will be used.
modalboolean
Whether the menu should be the only visible content for screen readers, when set to true:
- interaction with outside elements will be disabled.
- scroll will be locked.
- focus will be locked inside the menu content.
- elements outside the menu content will not be visible for screen readers.
preventScrollboolean
Whether the scroll should be locked even if the menu is not modal.
forceMountboolean
Used to force mounting the menu (portal and content) when more control is needed. Useful when controlling animation with SolidJS animation libraries.

DropdownMenu.Root also accepts the following props to customize the placement of the DropdownMenu.Content.

PropDescription
getAnchorRect(anchor?: HTMLElement) => AnchorRect | undefined
Function that returns the trigger element's DOMRect.
placementPlacement
The placement of the menu content.
gutternumber
The distance between the menu content and the trigger element. By default, it's 0 plus half of the arrow offset, if it exists.
shiftnumber
The skidding of the menu content along the trigger element.
flipboolean | string
Controls the behavior of the menu content when it overflows the viewport:
- If a boolean, specifies whether the menu content should flip to the opposite side when it overflows.
- If a string, indicates the preferred fallback placements when it overflows.
The placements must be spaced-delimited, e.g. "top left".
slideboolean
Whether the menu content should slide when it overflows.
overlapboolean
Whether the menu content can overlap the trigger element when it overflows.
sameWidthboolean
Whether the menu content should have the same width as the trigger element. This will be exposed to CSS as --kb-popper-anchor-width.
fitViewportboolean
Whether the menu content should fit the viewport. If this is set to true, the menu content will have maxWidth and maxHeight set to the viewport size. This will be exposed to CSS as --kb-popper-content-available-width and --kb-popper-content-available-height.
hideWhenDetachedboolean
Whether to hide the menu content when the trigger element becomes occluded.
detachedPaddingnumber
The minimum padding in order to consider the trigger element occluded.
arrowPaddingnumber
The minimum padding between the arrow and the menu content corner.
overflowPaddingnumber
The minimum padding between the menu content and the viewport edge. This will be exposed to CSS as --kb-popper-overflow-padding.

DropdownMenu.Trigger consists of Button.

Data attributeDescription
data-expandedPresent when the menu is open.
data-closedPresent when the menu is close.

DropdownMenu.Icon, DropdownMenu.Content, DropdownMenu.SubTrigger and DropdownMenu.SubContent share the same data-attributes.

PropDescription
onOpenAutoFocus(event: Event) => void
Event handler called when focus moves into the component after opening. It can be prevented by calling event.preventDefault.
onCloseAutoFocus(event: Event) => void
Event handler called when focus moves to the trigger after closing. It can be prevented by calling event.preventDefault.
onEscapeKeyDown(event: KeyboardEvent) => void
Event handler called when the escape key is down. It can be prevented by calling event.preventDefault.
onPointerDownOutside(event: PointerDownOutsideEvent) => void
Event handler called when a pointer event occurs outside the bounds of the component. It can be prevented by calling event.preventDefault.
onFocusOutside(event: FocusOutsideEvent) => void
Event handler called when the focus moves outside the bounds of the component. It can be prevented by calling event.preventDefault.
onInteractOutside(event: InteractOutsideEvent) => void
Event handler called when an interaction (pointer or focus event) happens outside the bounds of the component. It can be prevented by calling event.preventDefault.
PropDescription
sizenumber
The size of the arrow.
PropDescription
textValuestring
Optional text used for typeahead purposes. By default, the typeahead behavior will use the .textContent of the DropdownMenu.ItemLabel part if provided, or fallback to the .textContent of the DropdownMenu.Item. Use this when the content is complex, or you have non-textual content inside.
disabledboolean
Whether the item is disabled or not.
closeOnSelectboolean
Whether the menu should close when the item is activated.
onSelect() => void
Event handler called when the user selects an item (via mouse or keyboard).
Data attributeDescription
data-disabledPresent when the item is disabled.
data-highlightedPresent when the item is highlighted.

DropdownMenu.ItemLabel, DropdownMenu.ItemDescription and DropdownMenu.ItemIndicator shares the same data-attributes.

PropDescription
forceMountboolean
Used to force mounting when more control is needed. Useful when controlling animation with SolidJS animation libraries.
PropDescription
valuestring
The controlled value of the menu radio item to check.
defaultValuestring
The value of the menu radio item that should be checked when initially rendered. Useful when you do not need to control the state of the radio group.
onChange(value: string) => void
Event handler called when the value changes.
disabledboolean
Whether the radio group is disabled or not.
PropDescription
valuestring
The value of the menu item radio.
textValuestring
Optional text used for typeahead purposes. By default, the typeahead behavior will use the .textContent of the DropdownMenu.ItemLabel part if provided, or fallback to the .textContent of the DropdownMenu.Item. Use this when the content is complex, or you have non-textual content inside.
disabledboolean
Whether the item is disabled or not.
closeOnSelectboolean
Whether the menu should close when the item is checked.
onSelect() => void
Event handler called when the user selects an item (via mouse or keyboard).
Data attributeDescription
data-disabledPresent when the item is disabled.
data-checkedPresent when the item is checked.
data-highlightedPresent when the item is highlighted.
PropDescription
checkedboolean
The controlled checked state of the item.
defaultCheckedboolean
The default checked state when initially rendered. Useful when you do not need to control the checked state.
onChange(checked: boolean) => void
Event handler called when the checked state of the item changes.
textValuestring
Optional text used for typeahead purposes. By default, the typeahead behavior will use the .textContent of the DropdownMenu.ItemLabel part if provided, or fallback to the .textContent of the DropdownMenu.Item. Use this when the content is complex, or you have non-textual content inside.
indeterminateboolean
Whether the item is in an indeterminate state.
disabledboolean
Whether the item is disabled or not.
closeOnSelectboolean
Whether the menu should close when the item is checked/unchecked.
onSelect() => void
Event handler called when the user selects an item (via mouse or keyboard).
Data attributeDescription
data-disabledPresent when the item is disabled.
data-indeterminatePresent when the item is in an indeterminate state.
data-checkedPresent when the item is checked.
data-highlightedPresent when the item is highlighted.
PropDescription
openboolean
The controlled open state of the sub menu.
defaultOpenboolean
The default open state when initially rendered. Useful when you do not need to control the open state.
onOpenChange(open: boolean) => void
Event handler called when the open state of the sub menu changes.

DropdownMenu.Sub also accepts the following props to customize the placement of the DropdownMenu.SubContent.

PropDescription
getAnchorRect(anchor?: HTMLElement) => AnchorRect | undefined
Function that returns the trigger element's DOMRect.
gutternumber
The distance between the sub menu content and the trigger element. By default, it's 0 plus half of the arrow offset, if it exists.
shiftnumber
The skidding of the sub menu content along the trigger element.
slideboolean
Whether the sub menu content should slide when it overflows.
overlapboolean
Whether the sub menu content can overlap the trigger element when it overflows.
fitViewportboolean
Whether the sub menu content should fit the viewport. If this is set to true, the sub menu content will have maxWidth and maxHeight set to the viewport size. This will be exposed to CSS as --kb-popper-content-available-width and --kb-popper-content-available-height.
hideWhenDetachedboolean
Whether to hide the sub menu content when the trigger element becomes occluded.
detachedPaddingnumber
The minimum padding in order to consider the trigger element occluded.
arrowPaddingnumber
The minimum padding between the arrow and the sub menu content corner.
overflowPaddingnumber
The minimum padding between the sub menu content and the viewport edge. This will be exposed to CSS as --kb-popper-overflow-padding.
PropDescription
textValuestring
Optional text used for typeahead purposes. By default, the typeahead behavior will use the .textContent of the DropdownMenu.SubTrigger. Use this when the content is complex, or you have non-textual content inside.
disabledboolean
Whether the sub menu trigger is disabled or not.
Data attributeDescription
data-disabledPresent when the item is disabled.
data-highlightedPresent when the item is highlighted.
PropDescription
onEscapeKeyDown(event: KeyboardEvent) => void
Event handler called when the escape key is down. It can be prevented by calling event.preventDefault.
onPointerDownOutside(event: PointerDownOutsideEvent) => void
Event handler called when a pointer event occurs outside the bounds of the component. It can be prevented by calling event.preventDefault.
onFocusOutside(event: FocusOutsideEvent) => void
Event handler called when the focus moves outside the bounds of the component. It can be prevented by calling event.preventDefault.
onInteractOutside(event: InteractOutsideEvent) => void
Event handler called when an interaction (pointer or focus event) happens outside the bounds of the component. It can be prevented by calling event.preventDefault.

Rendered elements

ComponentDefault rendered element
DropdownMenu.Rootnone
DropdownMenu.Triggerbutton
DropdownMenu.Iconspan
DropdownMenu.PortalPortal
DropdownMenu.Contentdiv
DropdownMenu.Arrowdiv
DropdownMenu.Separatorhr
DropdownMenu.Groupdiv
DropdownMenu.GroupLabelspan
DropdownMenu.Subnone
DropdownMenu.SubTriggerdiv
DropdownMenu.SubContentdiv
DropdownMenu.Itemdiv
DropdownMenu.ItemLabeldiv
DropdownMenu.ItemDescriptiondiv
DropdownMenu.ItemIndicatordiv
DropdownMenu.RadioGroupdiv
DropdownMenu.RadioItemdiv
DropdownMenu.CheckboxItemdiv

Accessibility

Keyboard Interactions

KeyDescription
SpaceWhen focus is on the trigger, opens the menu and focuses the first item.
When focus is on an item, activates the item.
EnterWhen focus is on the trigger, opens the menu and focuses the first item.
When focus is on an item, activates the item.
ArrowDownWhen focus is on the trigger, opens the menu and focuses the first item.
When focus is on an item, moves focus to the next item.
ArrowUpWhen focus is on the trigger, opens the menu and focuses the last item.
When focus is on an item, moves focus to the previous item.
ArrowRight / ArrowLeftWhen focus is on a sub menu trigger, opens or closes the submenu depending on reading direction.
HomeWhen focus is on an item, moves focus to first item.
EndWhen focus is on an item, moves focus to last item.
EscCloses the menu and moves focus to the trigger.