import { DropdownMenu } from '@uhg-abyss/web/ui/DropdownMenu';Overview
The DropdownMenu component displays a menu triggered by a button, known as the Action Menu. This menu can contain various items, including action items, checkboxes, radio groups, and submenus. Each item can have an icon.
Label
Use the label prop to set the text displayed on the trigger. Alternatively, you can use the iconOnly prop to display only an icon without text.
Note: To meet accessibility standards, you must still provide a label prop when using iconOnly.
Outline
Use the outline prop to control the outline of the Dropdown menu. The default is true. When setting the prop to false, the border radius will be removed and the component will have a flat appearance.
Note: An outline should be used if the DropdownMenu is used on a background that does not meet the 3:1 color contrast ratio.
isDisabled
Use the isDisabled prop to disable the DropdownMenu.
isLoading
Use the isLoading prop to place the Action Menu in a loading state. This will display a loading spinner in place of the menu items while the menu is loading.
You can also provide the optional prop loadingLabel for additional context when the menu is in a loading state. This prop takes the form of an object, as explained in our LoadingSpinner documentation.
Menu items
Use the menuItems prop to specify what will be displayed in the Action Menu. The prop requires an array of objects that have the following forms:
Action item
interface ActionMenuItemProps { title: string; onClick: Function; icon: ReactNode; //optional isSeparated: boolean; //optional disabled: boolean; //optional}Checkbox
interface ActionMenuCheckboxItemProps { checkboxes: Array<{ label: string; checked: bool; onChange: func; disabled: bool; //optional }>;}Radio group
interface ActionMenuRadioItemProps { label: string; value: string; onChange: Function; radios: Array<{ label: string; value: string; disabled: bool; //optional }>;}Submenu
interface ActionMenuItemGroupSubMenuItem { title: string; subMenu: ActionMenuItemGroupItem[]; // any of the above types}Inserting icons
There are three different types of icons that can be added to the DropdownMenu:
- Use the
beforeprop to insert an icon before the trigger label. - Use the
iconOnlyprop to only display an icon in the trigger button without displaying the label. - The
iconOnlyprop can be used to display only an icon in the trigger button without displaying the label.iconOnlyalso accepts a React node, allowing you to use any custom icon component.
- Use the
iconprop in the menu items to insert icons before to the item title. While this prop accepts any React node, the examples on this page use our IconSymbol component.
onClick
Use the onClick function on each menu item to trigger a custom function when that item is clicked.
onChange
Use the onChange function to trigger a custom function when a checkbox or a radio item is clicked. You can use this to update your checked state, among other things.
Disabled menu items
When the disabled flag is set to true on a menu item, that item cannot be interacted with. This prop applies to all item types, including action items, checkboxes, and radio groups. The item will be visually styled to indicate that it is disabled.
isSeparated
When the isSeparated flag is set to true on a menu item, a horizontal divider will be inserted after that item. Checkbox and radio group items automatically render a divider both before and after the item, so no isSeparated flag is required. A divider will not be rendered before the first item or after the last item.
onOutsideClick
Use onOutsideClick prop to trigger a custom function when the user clicks outside an open menu.
Dropdown open state
Use the open and onOpenChange props together to control the dropdown open state. open is a boolean that determines whether the dropdown is open or closed, and onOpenChange is a function that is called when the open state changes. This allows you to manage the open state of the dropdown programmatically.
Height
Use the height prop to set a custom height for the Action Menu. The default height is 500px. This prop accepts any valid CSS height value.
SplitButton vs. DropdownMenu
DropdownMenu is a versatile component that can be used for various menu actions, while SplitButton is specifically designed for a button with a dropdown menu that allows users to perform an action or select from a list of options.SplitButton is more suitable when you want to combine a primary action with a secondary dropdown menu.
DropdownMenu Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
before | React.ReactNode | - | - | * A React node (IconSymbol) to be displayed before the label in the dropdown trigger. |
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
height | Property.Height | undefined | 500 | - | The height of the menu content area. |
iconOnly | React.ReactNode | false | - | If set to true, renders a standard icon button. If set to false, renders a button with a label. Alternatively, you can provide an IconSymbol to use a custom icon element. |
isDisabled | boolean | false | - | Disables the dropdown menu trigger and interactions. |
isLoading | boolean | false | - | Displays a loading state for the dropdown menu content. |
label | string | - | The label for the dropdown menu trigger. | |
loadingLabel | { heading: string; headingLevel?: 2 | 1 | 3 | 4 | 5 | 6 | undefined; bodyText?: string | undefined; } | undefined | - | - | The label shown when the dropdown content is loading. |
menuItems | GenericActionMenuItem[] | - | - | An array of menu items to be rendered in the dropdown. |
modal | boolean | true | - | Determines if the dropdown behaves as a modal dialog. |
onOpenChange | (open: boolean) => void | - | - | Callback fired when the dropdown menu open state changes. |
onOutsideClick | (event: MouseEvent | TouchEvent) => void | - | - | Callback fired when a click outside the dropdown menu is detected. |
open | boolean | null | 'null' | - | Controls the open state of the dropdown menu (controlled mode). |
outline | boolean | true | - | Applies an outline style to the dropdown menu trigger. |
ActionMenu - Menu Item Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disabled | boolean | false | - | If true, the menu item will be disabled |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
icon | React.ReactNode | '' | - | The icon type to display in the menu item |
isSeparated | boolean | false | - | If true, the menu item will be separated by a horizontal line |
onClick | (event: React.MouseEvent<HTMLLIElement, MouseEvent>) => void | - | - | Callback function when the menu item is clicked |
title | string | - | The title of the menu item |
ActionMenu - Checkbox Item Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
checkboxes | CheckboxOption[] | - | An array of checkbox options to display. Each checkbox option should include a label and optionally disabled, checked state, and change handler. | |
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
isSeparatedBottom | boolean | false | - | If true, a separator is shown below the last checkbox. |
isSeparatedTop | boolean | false | - | If true, a separator is shown above the first checkbox. |
ActionMenu - Radio Item Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disabled | boolean | false | - | If true, disables the entire radio group. |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
isSeparatedBottom | boolean | true | - | If true, a separator is shown below the radio group. |
isSeparatedTop | boolean | true | - | If true, a separator is shown above the radio group. |
label | string | '' | The label for the radio group. | |
onChange | (value: any) => void | - | - | Callback when the selected radio changes. |
radios | RadioOption[] | - | An array of radio items to display. Each radio item should include a label, value, and optionally disabled state. | |
value | any | - | The current value for the radio group. |
ActionMenu - Item Group Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
firstItemRef | React.Ref<HTMLElement> | - | - | The ref for the first item in the group. Typically used for focus control. |
menuItems | GenericActionMenuItem[] | - | - | An array of menu items. Each item can be a basic menu item, a submenu trigger, a checkbox group, or a radio group. |
width | string | number | - | - | The width that should be applied to the rendered menu group. |
ActionMenu - SubMenu Trigger Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disabled | boolean | false | - | Whether the sub menu trigger is disabled. |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
icon | React.ReactNode | '' | - | The icon type to display in the menu item |
isOpen | boolean | false | - | Whether the sub menu trigger is open. |
title | string | - | Title of the sub menu trigger item. |
DropdownMenu Classes
| Class Name | Description |
|---|---|
| .abyss-dropdown-menu-root | Root container for the dropdown menu |
| .abyss-dropdown-menu-portal | Portal container for the dropdown menu |
ActionMenu - Menu Item Classes
| Class Name | Description |
|---|---|
| .abyss-action-menu-item-list-item | List item element for the action menu item |
| .abyss-action-menu-item | Item element |
| .abyss-action-menu-item-left-container | Container for the icon in the item |
| .abyss-action-menu-item-title | Title text in the item |
ActionMenu - Checkbox Item Classes
| Class Name | Description |
|---|---|
| .abyss-action-menu-checkbox-list-item | List item element for the action menu item |
| .abyss-action-menu-checkbox | Checkbox item element |
| .abyss-action-menu-checkbox-icon | Checkbox icon element |
ActionMenu - Radio Item Classes
| Class Name | Description |
|---|---|
| .abyss-action-menu-radio-group-list-item | List item element for the entire radio group |
| .abyss-action-menu-radio-group | Container element for the radio group |
| .abyss-action-menu-radio-group-label | Label for the radio group |
| .abyss-action-menu-radio | Radio item element |
| .abyss-action-menu-radio-left-container | Container for the left region (icon) in the radio item |
| .abyss-action-menu-radio-icon | Indicator icon for the radio item |
| .abyss-action-menu-radio-title | Title of the radio item |
ActionMenu - SubMenu Trigger Classes
| Class Name | Description |
|---|---|
| .abyss-action-menu-sub-trigger | Sub trigger element |
| .abyss-action-menu-item-left-container | Container for the icon in the sub trigger |
| .abyss-action-menu-item-title | Title text in the sub trigger |
| .abyss-action-menu-sub-trigger-right-container | Container for the right side of the sub trigger, typically for the chevron icon |
| .abyss-action-menu-sub-trigger-icon-right | Icon element on the right side of the sub trigger, typically a chevron icon |
ActionMenu - Menu Content Classes
| Class Name | Description |
|---|---|
| .abyss-action-menu-content | Container for the menu content |
| .abyss-action-menu-content-list | List container for the menu content items |
| .abyss-action-menu-content-theme | Theme container for styling the menu content |
ActionMenu - Menu Separator Classes
| Class Name | Description |
|---|---|
| .abyss-action-menu-item-separator | Root element for the menu separator |
Use for application menu settings and actions only - NOT navigation
From an accessibility and WAI-ARIA perspective, dropdown and split button menus are intended only for application settings and actions—not navigation. Unlike navigation components, these rely solely on arrow keys for making selections. When using navigation components, tabbing between links is an expected behavior. Use NavMenu or other components for navigating between web pages.
WAI-ARIA implementation
This component implements several WAI-ARIA design patterns beginning with Menu Button. Nested menus are of single-menu examples from Menu Bar (using roving tabindex to manage focus movement). Radio button and checkbox option operation are based upon the Editor Menu Example.
Keyboard Interactions
| Key | Description |
|---|---|
| Tab | Moves focus to the next focusable element. |
| Enter | If focus is on a Dropdown menu button, opens the relevant Dropdown menu. If focus is on a menu item with a trigger, opens the relevant sub-menu. If focus is on radio button or checkbox, will select/deselect it. |
| Space | If focus is on a Dropdown menu button, opens the relevant Dropdown menu. If focus is on a menu item with a trigger, opens the relevant sub-menu. If focus is on radio button or checkbox, will select/deselect it. |
| Escape | Closes open Dropdown menu and moves focus to its Dropdown menu button. |
| Up Arrow | Focuses the previous menu item. |
| Down Arrow | Focuses the next menu item. |
| Right Arrow | Opens a sub-menu if focus is on a menu item with a trigger. |
| Left Arrow | Closes a sub-menu if open. |
| Home | Moves focus to the first item in the Dropdown menu. |
| End | Moves focus to the last item in the Dropdown menu. |
Component Tokens
Note: Click on the token row to copy the token to your clipboard.
DropdownMenu Tokens
| Token Name | Value | |
|---|---|---|
| dropdown-menu.color.border.button | #002677 | |
| dropdown-menu.color.icon.secondary.default | #002677 | |
| dropdown-menu.color.icon.secondary.disabled | #4B4D4F | |
| dropdown-menu.color.icon.tertiary.rest | #196ECF | |
| dropdown-menu.color.icon.tertiary.hover | #004BA0 | |
| dropdown-menu.color.icon.tertiary.active | #002677 | |
| dropdown-menu.color.icon.tertiary.disabled | #7D7F81 | |
| dropdown-menu.color.icon.tertiary.selected | #196ECF | |
| dropdown-menu.color.surface.container.rest | #FFFFFF | |
| dropdown-menu.color.surface.container.hover | #F3F3F3 | |
| dropdown-menu.color.surface.container.active | #E5E5E6 | |
| dropdown-menu.color.surface.container.disabled | #F3F3F3 | |
| dropdown-menu.color.surface.container.selected | #EDF3FB | |
| dropdown-menu.color.text.label.secondary.default | #002677 | |
| dropdown-menu.color.text.label.secondary.disabled | #4B4D4F | |
| dropdown-menu.color.text.label.tertiary.rest | #196ECF | |
| dropdown-menu.color.text.label.tertiary.hover | #004BA0 | |
| dropdown-menu.color.text.label.tertiary.active | #002677 | |
| dropdown-menu.color.text.label.tertiary.disabled | #7D7F81 | |
| dropdown-menu.color.text.label.tertiary.selected | #196ECF | |
| dropdown-menu.border-radius.all.container | 500px | |
| dropdown-menu.border-width.all.button | 1px | |
| dropdown-menu.sizing.all.icon.utility | 20px | |
| dropdown-menu.sizing.height.button | 40px | |
| dropdown-menu.sizing.width.button | 40px | |
| dropdown-menu.spacing.gap.horizontal.button | 8px | |
| dropdown-menu.spacing.gap.vertical.button-dropdown | 8px | |
| dropdown-menu.spacing.padding.all.icon-only | 8px | |
| dropdown-menu.spacing.padding.left.default | 16px | |
| dropdown-menu.spacing.padding.right.default | 12px | |
| dropdown-menu.spacing.padding.horizontal.leading-icon | 12px | |
| dropdown-menu.spacing.padding.vertical.button | 8px |
ActionMenu Tokens
| Token Name | Value | |
|---|---|---|
| action-menu.color.border.container | #CBCCCD | |
| action-menu.color.surface.container | #FFFFFF | |
| action-menu.color.surface.menu-item.rest | #FFFFFF | |
| action-menu.color.surface.menu-item.hover | #F3F3F3 | |
| action-menu.color.surface.menu-item.active | #E5E5E6 | |
| action-menu.color.surface.separator | #CBCCCD | |
| action-menu.color.text.menu-item.default | #4B4D4F | |
| action-menu.color.text.menu-item.disabled | #7D7F81 | |
| action-menu.color.icon.menu-item.default | #323334 | |
| action-menu.color.icon.menu-item.disabled | #7D7F81 | |
| action-menu.border-radius.all.container | 4px | |
| action-menu.border-width.all.container | 1px | |
| action-menu.spacing.gap.horizontal.menu-item | 8px | |
| action-menu.spacing.margin.all.separator | 8px | |
| action-menu.spacing.padding.horizontal.menu-item | 16px | |
| action-menu.spacing.padding.vertical.loading | 24px | |
| action-menu.spacing.padding.vertical.menu-item | 8px |