<ui-toolbar>

A toolbar groups related controls (buttons, links, selects) into a single keyboard-navigable strip using the WAI-ARIA APG Toolbar pattern and roving tabindex. Use <ui-toolbar> when controls belong together conceptually and you want arrow-key navigation within the group; use an ordinary <menu> or a <nav> when the controls are standalone links that don't need arrow-key movement. Source: ui-toolbar.mjs.

Accessibility (WCAG)

ElementAttributesPropertiesMethodsEvents
<ui-toolbar> aria-orientation, aria-label, selector .items refresh_tabstop() ui-toolbar-focus

selector defaults to :scope > button, so without it the toolbar manages only its direct <button> children. Nested buttons and links are left alone.

The component sets focus behaviour, not layout. ui.css has no rule for <ui-toolbar>, so it displays inline and its items flow like ordinary text. The demos on this page get their row and column layout from this page's own stylesheet: ui-toolbar { display: flex; gap: var(--size-1); }, plus flex-direction: column for aria-orientation="vertical". Copy that rule when you reuse a demo.

1. Basic horizontal

Horizontal toolbar with three buttons. Left/Right arrow keys move focus.

Show code

2. Vertical toolbar

Vertical toolbar with aria-orientation="vertical". Up/Down arrow keys navigate.

Show code

3. Disabled buttons — the two patterns

Both buttons below are unavailable and both are dimmed, so they look alike. They behave differently on purpose: Skipped carries disabled and arrow-key navigation skips it, while Navigable carries aria-disabled="true" and the arrows stop on it. Tab into the row and use the arrows to move across it — the log records focus and click events.

Navigable is appropriate when discovering the disabled functionality matters, which is the criterion the APG Toolbar pattern names: keyboard and screen-reader users can focus the control to discover it and read its tooltip explanation. It has to be aria-disabled rather than disabled because a natively-disabled element cannot be focused at all — so keeping a control focusable requires an alternative to disabled. Navigable does not mean activatable: <ui-toolbar> stops a click on such an item, so it cannot be activated, consistent with its announced state.

Show code

4. Custom selector

The selector attribute controls which elements are managed. Here with selector="a".

Link 1 Link 2 Link 3
Show code

5. Dynamic items

Add/remove buttons dynamically. Call refresh_tabstop() to re-initialise the roving tabindex.

Show code

6. Keyboard navigation

Focus the toolbar and navigate with arrow keys, Home and End. Events are logged.

Show code

7. Mirroring the focused item elsewhere

When another part of the page needs to reflect the toolbar’s focused item — a preview pane, a second window, a detail panel — listen for ui-toolbar-focus. It carries detail: {item, index}, bubbles, and fires for every way an item can take focus: the arrows, Home/End, a click, and Tab into the toolbar.

Prefer it over a plain focusin listener. It fires only for managed items, so a focusable element outside the selector — the search field below, a control nested inside an item, a nested listbox()'s options — does not produce this event. With a general focus listener, each consumer would need to check the selector itself. Focus each control below and compare the two log lines.

ui-toolbar-focus reports focus changes. It does not fire for refresh_tabstop(), which resets the tab stop without a user gesture. This prevents a preview from resetting whenever the toolbar re-renders.

Mirror: nothing yet

Show code

See also