- Home
- Design system
- Elements
- Menubutton
Menubutton
Menubutton is for dynamically displaying navigation menus
Overview
The ds-menubutton component displays a navigation or action menu from a button-like trigger. It supports native popover or details and summary implementations and uses ds-menu for the menu content.
Options
Basic usage
ds-menubutton can use either a div and button with native popover state, or native HTML details and summary elements. The popover implementation is recommended for new menubuttons.
ds-menu content uses the available options of ds-menu. See ds-menu for additional documentation on menu items.
Using popover
The native Popover API is the recommended way to open and close the menu. Match the button’s popovertarget value to the menu’s id, and add the popover attribute to the menu. The browser manages the expanded state, light dismissal, and Escape key behavior without additional JavaScript.
popovertarget provides the implicit aria-expanded state and relationship between the button and popover, so these do not need to be added or synchronized manually. Retain aria-haspopup="menu" to identify the type of popup. See Role and ARIA attributes. Using details/summary elements
details and summary implementation remains supported for existing uses. When using a details element, clicking the summary element toggles the ds-menu content without JavaScript.
Using JavaScript
Assign popoverTargetElement when application logic needs to connect the trigger and menu programmatically. This is the JavaScript equivalent of the popovertarget attribute, so the browser still manages the expanded state and native popover behavior.
Position
By default the menubutton menu is displayed below and aligned to the left of the button element.
As an alternative, the following positions are supported:
ds-header__controls element will automatically display aligned right. Component colors
Adding a color the to the top-level ds-menubutton element will color the button and the drop down menu.
If you need to only color the button (and not the drop down menu), add the color to the ds-button element.
Color the button and menu
Color the button only
Width
Narrow, mid, wide, full
--full width sets the menu to be the same width of the menubutton
Height
By default the menu will be the height of the menu contents. You can also restrict the overall height of the menu and cause the contents to scroll. If the menu can scroll, a shadow will be added at the bottom/top of the menu to indicate the menu is scrollable.
You can apply these settings to either a ds-menubutton or to a standalone ds-menu component.
There are two ways to restrict the height.
Restrict the height to the viewport
Adding the class --viewport to the menu will restrict the height to 100vh - --ds-header-height (usually 100vh - 60px) and force the menu to scroll.
Restrict the height to a specific size
You can restrict the height by changing the --ds-menu-height value (either in a css file, inline style tag or via javascript).
let myCustomMenu = document.getElementById('customMenu');
myCustomMenu.style.setProperty('--ds-menu-height', '400px');
Styles
Variants
No dismiss
To prevent clicking outside the menu from closing it, use popover="manual" with the popover implementation. Use the class --no-dismiss with the details implementation.
No background
To not show the background modal tint, use the class --no-background.
Inline
To show the open menu in the normal document flow, use the class --inline.
--inline is only supported with the details and summary implementation. It cannot be used with popover, because an open popover is rendered in the top layer and does not expand the surrounding layout. Addon menubutton
The --addon styles slightly modify the menubutton to ‘join’ the containing component.
Accessibility
References
Implementation
There are two primary usage cases for ds-menubutton
Navigation menubutton
Navigation menu buttons primarily contain lists of links that change the URL and display a different page or context. Retain the native list and link semantics rather than adding menu and menuitem roles.
Native details and popover implementations provide their own expanded state. A scripted button must maintain its aria-expanded state as described below.
Action menubutton
Action menu buttons are a menu that performs a task on the page, such as opening a modal, changing the status of a feature etc.
This component is not fully accessible by default when used for action menus. Action menus require the complete ARIA menu roles and keyboard interactions described by the WAI-ARIA Menu Button Pattern.
Role and ARIA attributes
The trigger attributes depend on the state mechanism used by the menubutton.
Native popover state
Match popovertarget to the popover menu’s id. The browser manages the expanded state, so do not add a duplicate aria-expanded attribute.
Native details state
Do not add aria-expanded or button roles to summary. The browser exposes the expanded state of the native details element.
Scripted button state
Set aria-expanded to match the visible menu state. aria-controls references the menu content by id.
| Attribute | Required | Type | Description |
|---|---|---|---|
aria-haspopup=“menu” | Required | Static | Indicates that the button opens a menu |
aria-expanded | Required | Dynamic | Set to true when the menu is open and false when it is closed |
aria-controls | Optional | Static | References the menu content controlled by the button |
The following additional roles apply when implementing the complete ARIA action-menu interaction pattern:
| Element | Attribute | Required | Type | Description |
|---|---|---|---|---|
<div> | role=“menu” | Required | Static | Indicates the element is a menu |
<ul> | role=“none” | Required | Static | Hides implied semantics from assistive technologies |
<li> | role=“none” | Required | Static | Hides implied semantics from assistive technologies |
<a> | role=“menuitem” | Required | Static | Indicates the element is a menuitem |
tabindex=“-1” | Required | Static | Prevents list items being selected using the tab keyboard command |
Keyboard access
The trigger can be reached with the browser’s native Tab behavior. Native details and popover triggers open with Space or Enter; a scripted trigger must implement that state change. Opening a native details or popover menu does not automatically move focus to its first menu item.
When used as an action menubutton, additional roles, ARIA attributes, focus management, and JavaScript keyboard handling are required.
Menu button - the closed menu button is selected:
| Key | Required | Support | Description |
|---|---|---|---|
Enter | Required | Native details/popover; JavaScript for scripted state and focus | Opens the menu; action-menu implementations move focus to the first menu item |
Space | Required | Native details/popover; JavaScript for scripted state and focus | Opens the menu; action-menu implementations move focus to the first menu item |
Tab | Required | Native | Moves to the next element in the page tab sequence |
Down Arrow | Optional | JavaScript | Opens the menu and moves focus to the first menu item |
Up Arrow | Optional | JavaScript | Opens the menu and moves focus to the last menu item |
Menu items - the menubutton menu is open:
| Key | Required | Support | Description |
|---|---|---|---|
Enter | Required | Native | Activates the selected menu item |
Escape | Required | Native popover; JavaScript otherwise | 1. Closes the menu 2. Moves focus back to the menu button |
Tab | Required | JavaScript | 1. Closes the menu 2. Move to the next element in the page tab sequence |
Down Arrow | Optional | JavaScript | Moves focus to the next menu item |
Up Arrow | Optional | JavaScript | Moves focus to the previous menu item |
JavaScript
Use showPopover(), hidePopover(), and togglePopover() to control a menu from application logic. Passing the trigger as source preserves its relationship with the popover when it is shown programmatically.
const trigger = document.querySelector('[popovertarget="account-menu"]');
const menu = trigger.popoverTargetElement;
function openMenu() {
menu.showPopover({ source: trigger });
}
function closeMenu() {
menu.hidePopover();
}
function toggleMenu() {
return menu.togglePopover({ source: trigger });
}
Examples
Menubutton inside other components
When ds-menubutton is used inside ds-select, ds-input, or ds-range it will be displayed next to the element and will not wrap when the window is scaled.
Menu item button with alert visual state
Header example
ds-menubutton inside ds-datatable
| Heading one | Heading two | Heading three |
|---|---|---|
| Content | Content | |
| Content | Content |
| Heading one | Heading two | Heading three |
|---|---|---|
| Content | Content | |
| Content | Content |
Manifest
The component manifest describes this component's API: its modifiers, structure, data attributes, CSS custom properties, accessibility notes, and example markup. It is consumed by tooling such as AI assistants and code generators.
Latest version: https://assets.soracom.io/sds/3.39.6/ds-menubutton/manifest.json?v=3.39.6