import { SplitButton } from '@uhg-abyss/web/ui/SplitButton';Overview
The SplitButton component is a button that has a main action and a dropdown menu. It is used to display a set of actions or functions that can be triggered by the user. The component is designed to be flexible and customizable, allowing you to define the menu items, their actions, and how they are displayed.
The dropdown, known as the Action Menu, can contain single menu items, checkboxes, radio groups, and submenus. Each item can have an icon.
Label
Use the label prop to set the text of the main action button.
Outline
Use the outline prop to control the outline of the SplitButton. 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 SplitButton is used on a background that does not meet the 3:1 color contrast ratio.
isDisabled
Use the isDisabled prop to disable the entire SplitButton
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 two types of icons that can be added to the SplitButton:
- Use the
beforeprop to insert an icon before the main action button label. - 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
There are two types of onClick functions you can use with the SplitButton:
- To provide an action to perform when clicking the main action button, use the
onClickprop of theSplitButtoncomponent. - To provide an action to perform when clicking a menu item, use the
onClickprop of the menu item object.
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.
SplitButton 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. |
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?: 5 | 1 | 2 | 3 | 4 | 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. |
onClick | (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void | - | - | Callback fired when the main action button is clicked. This is the action that occurs when the user clicks the main part of the split button. |
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. |
SplitButton Classes
| Class Name | Description |
|---|---|
| .abyss-action-menu-root | Root element for the Action Menu within Split Button |
| .abyss-split-button-root | Container element for Split Button |
| .abyss-action-menu-portal | Portal element for the Action Menu within Split Button |
| .abyss-split-button-trigger | Trigger button element for the dropdown part of Split Button |
| .abyss-split-button-trigger-icon | Icon element inside the trigger button of Split Button |
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.
SplitButton Tokens
| Token Name | Value | |
|---|---|---|
| split-button.color.border.outline-button.default | #002677 | |
| split-button.color.border.outline-button.disabled | #CBCCCD | |
| split-button.color.border.text-button.rest | #196ECF | |
| split-button.color.border.text-button.hover | #004BA0 | |
| split-button.color.border.text-button.active | #002677 | |
| split-button.color.border.text-button.disabled | #7D7F81 | |
| split-button.color.icon.outline-button.default | #002677 | |
| split-button.color.icon.outline-button.disabled | #4B4D4F | |
| split-button.color.icon.text-button.rest | #196ECF | |
| split-button.color.icon.text-button.hover | #004BA0 | |
| split-button.color.icon.text-button.active | #002677 | |
| split-button.color.icon.text-button.disabled | #7D7F81 | |
| split-button.color.icon.text-button.selected | #196ECF | |
| split-button.color.surface.container.rest | #FFFFFF | |
| split-button.color.surface.container.hover | #F3F3F3 | |
| split-button.color.surface.container.active | #E5E5E6 | |
| split-button.color.surface.container.disabled | #F3F3F3 | |
| split-button.color.text.label.outline-button.default | #002677 | |
| split-button.color.text.label.outline-button.disabled | #4B4D4F | |
| split-button.color.text.label.text-button.rest | #196ECF | |
| split-button.color.text.label.text-button.hover | #004BA0 | |
| split-button.color.text.label.text-button.active | #002677 | |
| split-button.color.text.label.text-button.disabled | #7D7F81 | |
| split-button.border-radius.all.container | 500px | |
| split-button.border-width.all.container | 1px | |
| split-button.sizing.all.icon.utility | 20px | |
| split-button.spacing.gap.horizontal.button | 8px | |
| split-button.spacing.gap.vertical.button-dropdown | 8px | |
| split-button.spacing.padding.left.button | 16px | |
| split-button.spacing.padding.right.label | 8px | |
| split-button.spacing.padding.right.menu-trigger | 8px | |
| split-button.spacing.padding.vertical.menu-trigger | 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 |