Skip to main content

DropdownMenu

Displays a menu triggered by a button, such as a set of actions or functions.

github
View source code

Migration Information

For teams migrating from the V1 to V2 component, please refer to the migration guide for changes to the component.
Component Guide
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.

Always use a label

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.

Important

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.

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
}>;
}
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 before prop to insert an icon before the trigger label.
  • Use the iconOnly prop to only display an icon in the trigger button without displaying the label.
  • The iconOnly prop can be used to display only an icon in the trigger button without displaying the label.
    • iconOnly also accepts a React node, allowing you to use any custom icon component.
  • Use the icon prop 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.

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.

NameTypeDefaultRequiredDescription
before
React.ReactNode | undefined
--
* A React node (IconSymbol) to be displayed before the label in the dropdown trigger.
height
React.CSSProperties['height'] | undefined
500
-
The height of the menu content area.
iconOnly
boolean | React.ReactNode | undefined
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 | undefined
false
-
Disables the dropdown menu trigger and interactions.
isLoading
boolean | undefined
false
-
Displays a loading state for the dropdown menu content.
label
string
-
The label for the dropdown menu trigger.
loadingLabel
LoadingSpinnerProps['label'] | undefined
--
The label shown when the dropdown content is loading.
menuItems
ActionMenuItem[] | undefined
--
An array of menu items to be rendered in the dropdown.
modal
boolean | undefined
false
-
Determines if the dropdown behaves as a modal dialog.
Note: automatically set to false in shadow DOM contexts.
onOpenChange
(open: boolean) => void | undefined
--
Callback fired when the dropdown menu open state changes.
onOutsideClick
(event: MouseEvent | TouchEvent) => void | undefined
--
Callback fired when a click outside the dropdown menu is detected.
open
boolean | null | undefined
'null'
-
Controls the open state of the dropdown menu (controlled mode).
outline
boolean | undefined
true
-
Applies an outline style to the dropdown menu trigger.

ActionMenu - Menu Item Props​

NameTypeDefaultRequiredDescription
disabled
boolean | undefined
false
-
If true, the menu item will be disabled
icon
React.ReactNode | undefined
''
-
The icon type to display in the menu item
isSeparated
boolean | undefined
false
-
If true, the menu item will be separated by a horizontal line
onClick
(event: Abyss.MouseClickEvent) => void | undefined
--
Callback function when the menu item is clicked
title
string
-
The title of the menu item

Below are the link(s) to the relevant GitHub type files:

Abyss.d.ts

ActionMenu - Checkbox Item Props​

NameTypeDefaultRequiredDescription
checkboxes
CheckboxOption[]
-
An array of checkbox options to display.
Each checkbox option should include a label and optionally disabled, checked state, and change handler.
isSeparatedBottom
boolean | undefined
false
-
If true, a separator is shown below the last checkbox.
isSeparatedTop
boolean | undefined
false
-
If true, a separator is shown above the first checkbox.

Below are the link(s) to the relevant GitHub type files:

Abyss.d.ts

ActionMenu - Radio Item Props​

NameTypeDefaultRequiredDescription
disabled
boolean | undefined
false
-
If true, disables the entire radio group.
isSeparatedBottom
boolean | undefined
true
-
If true, a separator is shown below the radio group.
isSeparatedTop
boolean | undefined
true
-
If true, a separator is shown above the radio group.
label
string
''
The label for the radio group.
onChange
(value: any) => void | undefined
--
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.

Below are the link(s) to the relevant GitHub type files:

Abyss.d.ts

ActionMenu - Item Group Props​

NameTypeDefaultRequiredDescription
firstItemRef
React.Ref<HTMLElement> | undefined
--
The ref for the first item in the group. Typically used for focus control.
menuItems
GenericActionMenuItem[] | undefined
--
An array of menu items. Each item can be a basic menu item,
a submenu trigger, a checkbox group, or a radio group.
width
number | string | undefined
--
The width that should be applied to the rendered menu group.

Below are the link(s) to the relevant GitHub type files:

Abyss.d.ts

ActionMenu - SubMenu Trigger Props​

NameTypeDefaultRequiredDescription
disabled
boolean | undefined
false
-
Whether the sub menu trigger is disabled.
icon
React.ReactNode | undefined
''
-
The icon type to display in the menu item
isOpen
boolean | undefined
false
-
Whether the sub menu trigger is open.
title
string
-
Title of the sub menu trigger item.

Below are the link(s) to the relevant GitHub type files:

Abyss.d.ts

Class NameDescription
.abyss-dropdown-menu-rootRoot container for the dropdown menu
.abyss-dropdown-menu-portalPortal container for the dropdown menu

ActionMenu - Menu Item Classes​

Class NameDescription
.abyss-action-menu-item-list-itemList item element for the action menu item
.abyss-action-menu-itemItem element
.abyss-action-menu-item-left-containerContainer for the icon in the item
.abyss-action-menu-item-titleTitle text in the item

ActionMenu - Checkbox Item Classes​

Class NameDescription
.abyss-action-menu-checkbox-list-itemList item element for the action menu item
.abyss-action-menu-checkboxCheckbox item element
.abyss-action-menu-checkbox-iconCheckbox icon element

ActionMenu - Radio Item Classes​

Class NameDescription
.abyss-action-menu-radio-group-list-itemList item element for the entire radio group
.abyss-action-menu-radio-groupContainer element for the radio group
.abyss-action-menu-radio-group-labelLabel for the radio group
.abyss-action-menu-radio-listList container for radio options in the group
.abyss-action-menu-radio-list-itemList item wrapper for each radio option
.abyss-action-menu-radioRadio item element
.abyss-action-menu-radio-left-containerContainer for the left region (icon) in the radio item
.abyss-action-menu-radio-iconIndicator icon for the radio item
.abyss-action-menu-radio-titleTitle of the radio item

ActionMenu - SubMenu Trigger Classes​

Class NameDescription
.abyss-action-menu-sub-triggerSub trigger element
.abyss-action-menu-item-left-containerContainer for the icon in the sub trigger
.abyss-action-menu-item-titleTitle text in the sub trigger
.abyss-action-menu-sub-trigger-right-containerContainer for the right side of the sub trigger, typically for the chevron icon
.abyss-action-menu-sub-trigger-icon-rightIcon element on the right side of the sub trigger, typically a chevron icon

ActionMenu - Menu Content Classes​

Class NameDescription
.abyss-action-menu-contentContainer for the menu content
.abyss-action-menu-content-listList container for the menu content items
.abyss-action-menu-content-themeTheme container for styling the menu content

ActionMenu - Menu Separator Classes​

Class NameDescription
.abyss-action-menu-item-separatorRoot 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.

By default, DropdownMenu uses non-modal behavior (modal={false}), so opening the menu does not apply aria-hidden to surrounding page landmarks.

Checkbox and radio indicators inside menu items use disabled native inputs with a silent aria-label="," so automated accessibility checks can validate labeling and nested-interactive behavior without changing keyboard interaction on the menu item itself.

Known Axe false positives​

When menus are displayed, Axe may report a region (moderate) issue because menu portal content may not be nested in <main> or another landmark. This is expected for this pattern because menu behavior is JavaScript-controlled and modal-like while open.

Known accessibility issues​

JAWS​

Radio button groups​

  • When there is only one group of radio buttons, the group name is only announced when first entered.
  • When there are multiple groups, the group name is consistently announced.

Keyboard Interactions​

KeyDescription
TabMoves focus to the next focusable element.
EnterIf 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.
SpaceIf 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.
EscapeCloses open Dropdown menu and moves focus to its Dropdown menu button.
Up ArrowFocuses the previous menu item.
Down ArrowFocuses the next menu item.
Right ArrowOpens a sub-menu if focus is on a menu item with a trigger.
Left ArrowCloses a sub-menu if open.
HomeMoves focus to the first item in the Dropdown menu.
EndMoves focus to the last item in the Dropdown menu.

Component Tokens​

Tip

Click on the token row to copy the token to your clipboard.

Token NameValue
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 NameValue
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
Table of Contents