Install
npm install a11y-command-menu-button
Plugin example
A compact command menu for application actions that need real buttons, roving focus, disabled states, one-level submenus, optional typeahead, and predictable focus restoration.
a11y-command-menu-buttonScenario
A support workspace needs a plus button beside a note field. Agents can upload files, insert saved templates, extract text when attachments are available, and understand unavailable actions before trying to activate them.
Live demo
The controls beside the example only change demo markup and initialization options. They do not add package behavior.
Keyboard walkthrough
Start the walkthrough, then use the command menu with keyboard only. The active step updates from demo events and focus changes.
Start by moving focus to the command menu trigger.
Reach the trigger Tab to the plus button. It has a usable accessible name.
Open the menu Press Enter, Space, ArrowDown, or ArrowUp.
Move between items Use arrows, Home, End, or type the first letters.
Enter and leave submenu Use ArrowRight to open Templates and ArrowLeft to return.
Close and restore focus Press Escape. Focus returns to the opener by default.
Developer notes
Import the package CSS, provide semantic menu markup, and initialize the root element. The demo uses the same public selectors as the README.
npm install a11y-command-menu-button
import { createCommandMenuButton } from "a11y-command-menu-button";
import "a11y-command-menu-button/styles.css";
const root = document.querySelector("[data-command-menu]");
if (root instanceof HTMLElement) {
createCommandMenuButton(root, {
hoverSubmenus: true,
mobileMode: "sheet",
portal: false,
typeahead: true
});
}
The package stylesheet includes a shortcut label class for visual hints. The label does not register a global keyboard shortcut; keep that routing in the host app so editable fields, platform conventions, and user settings can be respected.
<button
class="a11y-command-menu-button__item"
data-command-item
data-command-id="add-files"
type="button"
>
<span class="a11y-command-menu-button__item-label">Add files</span>
<span class="a11y-command-menu-button__shortcut" aria-hidden="true">U</span>
</button>
Use a real button for the trigger and real buttons or links for commands.
<div class="a11y-command-menu-button" data-command-menu>
<button
type="button"
class="a11y-command-menu-button__trigger"
data-command-trigger
aria-label="Open command menu"
aria-controls="command-menu"
>
<span aria-hidden="true">+</span>
</button>
<div id="command-menu" class="a11y-command-menu-button__panel" data-command-menu-panel hidden>
<button class="a11y-command-menu-button__item" data-command-item data-command-id="add-files">
Add files
</button>
</div>
</div>
| Option | Type | Demo value | Purpose |
|---|---|---|---|
typeahead |
boolean |
true |
Lets users type the first letters of enabled commands. |
hoverSubmenus |
boolean |
true |
Allows pointer hover to open one-level submenus. |
mobileMode |
"sheet" | "menu" |
"sheet" |
Uses bottom-sheet placement below the package mobile breakpoint. |
portal |
boolean |
Playground controlled | Moves menu and submenu layers to document.body. |
Accessibility behavior
This demo documents expected behavior from the plugin and sample markup. Test the final integration with your target assistive technologies and browser matrix.
<button> with a non-visual plus icon and an accessible name.aria-expanded, aria-controls, role="menu", and role="menuitem".tabindex; Tab exits and closes the menu.aria-disabled="true" commands remain discoverable but dispatch a disabled-command event.aria-busy="true" or data-command-loading remains keyboard discoverable but prevents command activation while busy.data-command-id values can reveal user intent when forwarded to analytics or logs.[data-command-menu] for the root.[data-command-trigger] for the trigger button.[data-command-menu-panel] for the menu layer.[data-command-item], [data-command-submenu-trigger], and [data-command-submenu] for commands and submenus.| Pattern | Support | Runtime or host responsibility |
|---|---|---|
| Top-level command opens one submenu | Supported | The plugin manages focus, aria-expanded, placement, and close behavior. |
| Submenu nested inside another submenu | Unsupported | The runtime logs a warning when nested data-command-submenu elements are detected. |
| Deep command hierarchy | Host-owned design decision | Flatten commands, split groups, or use a larger command palette/dialog pattern instead. |