J3W1 / DESIGN SYSTEM
Toolbar
A row of related controls under one tab stop with arrow-key movement; ghost buttons, a vertical separator, and a "more" button when the row overflows.
stable · LIGHT DOM · 1.1.0
Light DOM retains static content, native semantics, label relationships and host composition without duplicating controls.
Live variants
default
<j3w1-toolbar id="example-toolbar-default"><div class="toolbar" role="toolbar" aria-label="Editor" aria-orientation="horizontal">
<button class="toolbar-button" type="button" tabindex="0">Undo</button>
<button class="toolbar-button" type="button" tabindex="-1">Redo</button>
<div class="toolbar-separator" role="separator" aria-orientation="vertical"></div>
<button class="toolbar-button toolbar-button-demo-target" type="button" aria-pressed="false" tabindex="-1">Wrap</button>
<button class="toolbar-button" type="button" aria-pressed="true" tabindex="-1">Whitespace</button>
<div class="toolbar-separator" role="separator" aria-orientation="vertical"></div>
<button class="toolbar-button" type="button" tabindex="-1">Format</button>
</div></j3w1-toolbar>overflow
<j3w1-toolbar id="example-toolbar-overflow"><div class="toolbar" role="toolbar" aria-label="Editor" aria-orientation="horizontal">
<button class="toolbar-button" type="button" tabindex="0">Undo</button>
<button class="toolbar-button" type="button" tabindex="-1">Redo</button>
<div class="toolbar-separator" role="separator" aria-orientation="vertical"></div>
<button class="toolbar-button toolbar-button-demo-target" type="button" aria-pressed="false" tabindex="-1">Wrap</button>
<j3w1-menu><div class="menu"><button class="toolbar-button toolbar-more" type="button" id="example-toolbar-overflow-toolbar-more-trigger" aria-haspopup="menu" aria-expanded="false" aria-controls="example-toolbar-overflow-toolbar-more-menu" tabindex="-1">More</button><ul class="menu-list" role="menu" id="example-toolbar-overflow-toolbar-more-menu" aria-labelledby="example-toolbar-overflow-toolbar-more-trigger" hidden=""><li role="none"><button class="menu-item" type="button" role="menuitem" tabindex="-1" data-action="format">Format</button></li><li role="none"><button class="menu-item" type="button" role="menuitemcheckbox" tabindex="-1" aria-checked="false" data-action="whitespace">Show whitespace</button></li></ul></div></j3w1-menu>
</div></j3w1-toolbar>Install and register
Use the exact version. If npm publication is pending, install the release tarball from the installation guide.
npm install --save-exact @j3w1/ui@1.1.0import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/toolbar.css';
import '@j3w1/ui/register/toolbar';Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.
Copy the complete implementation
npx --package=@j3w1/ui@1.1.0 j3w1-ui copy toolbar --out ./vendor/j3w1/toolbarThe CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.
Public API
attributes
| Name | Type / signature | Meaning |
|---|---|---|
disabled | CustomEvent | Disable the native controls owned by this instance. |
loading | CustomEvent | Mark the primary control busy and prevent duplicate activation. |
properties
| Name | Type / signature | Meaning |
|---|---|---|
disabled | boolean | Delegates disabled state to native children. |
name | string | Native control name; application form keys remain explicit. |
methods
| Name | Type / signature | Meaning |
|---|---|---|
refresh | (): void | Reconnect behavior after replacing native child structure. |
focus | (options?: FocusOptions): void | Focus the first usable native control. |
events
| Name | Type / signature | Meaning |
|---|---|---|
j3w1-action | CustomEvent | A toggle action changed. |
Dependencies and verification
Registered components: menu. Style dependencies: menu.
Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.
Full implementation manifest, API and token dependency closure
Canonical specification
Purpose
Groups the frequent actions of a view into one row that costs one tab stop. A toolbar is for actions on the content beneath it; navigation between views belongs in tabs or the sidebar, and a set of mutually exclusive choices in a segmented control or radio group.
Anatomy
A div with role="toolbar" on color.surface.chrome with a 1px
color.border.divider bottom edge. Inside, ghost buttons in
color.text.default with a transparent 1px border, vertical separators in
color.border.default between groups, and in the overflow variant a trailing
“More” button that opens a menu with the controls that do not fit. Toggle
buttons carry aria-pressed.
States
| State | Visual | Non-colour channel |
|---|---|---|
| default | text color.text.default; no fill; transparent border | — |
| hover | background → color.interaction.hover.bg | cursor: pointer |
| focus-visible | ring 1px dashed color.interaction.focus.ring at −2px | the ring |
| disabled | text color.text.disabled; no fill; no hover | disabled; cursor: not-allowed; skipped by the arrow keys |
| toggled | fill color.interaction.pressed.bg; 1px color.border.active border; text color.text.bright | aria-pressed="true"; the border |
Pressing a button uses color.interaction.pressed.bg for the duration of
the press only; a toggled button keeps it.
Keyboard
The toolbar is one tab stop: the last focused control (initially the first
enabled one) has tabindex="0", every other control tabindex="-1". Left
and Right move between controls and wrap; Home and End jump to the ends;
Enter and Space activate. Disabled controls are skipped. Vertical toolbars
declare aria-orientation="vertical" and use Up and Down. Without script
every button is a tab stop, which is acceptable, not ideal.
Accessibility
aria-label names the toolbar; a page with several toolbars gives each a
distinct name. Toggle buttons expose aria-pressed; their label does not
change with the state. Separators are role="separator" with
aria-orientation="vertical" and are never focusable. Icon-only buttons
carry aria-label and a tooltip. Contrast: text 8.60:1 on the chrome
surface, toggled text 8.41:1 on the pressed fill, the toggled border 3.81:1,
ring 4.66:1. Every control is at least 24×24 CSS pixels with 4px between
neighbours in compact density.
Portability
Ghost buttons with a background and a border; the separator is a 1px rule. Toolkits with a native toolbar keep their own keyboard model and take the colours. The overflow menu is a menu component; hosts without one wrap the row instead and record the deviation.
Non-examples
Buttons with a visible border at rest. A filled primary button inside the
toolbar. Rounded buttons or a pill-shaped toolbar. Every button in the tab
order when script is available. A toggled state shown by colour alone without
aria-pressed. A toolbar that wraps to two lines. A separator that receives
focus. Disabling by opacity.