Toolbar
A toolbar is a container of related controls that acts as a single tab stop. Tab enters the toolbar once, and the arrow keys move between the controls inside it.
Most Terracotta composites navigate a specific child component. Toolbar
navigates any focusable descendant, so you can drop buttons, links, inputs and
<select> elements into it directly.
import { Toolbar } from 'terracotta/toolbar';Anatomy
<Toolbar> {/* role="toolbar", one tab stop, arrow-key navigation */}
{/* any focusable controls */}
</Toolbar>Examples
Horizontal (default)
The orientation is published as aria-orientation. One CSS rule then keeps the
layout and the semantics in step.
Vertical
<Toolbar class="toolbar" horizontal={false} aria-label="Tools">
<button type="button" class="toolbar-button">Select</button>
<button type="button" class="toolbar-button">Draw</button>
<button type="button" class="toolbar-button">Erase</button>
</Toolbar>With Terracotta controls
Toggle is a natural fit. Its tc-pressed attribute gives you the active state
for free:
With separators and groups
The arrow keys skip non-focusable elements, so separators need no special handling:
<Toolbar class="toolbar" aria-label="Editor">
<button type="button" class="toolbar-button">Undo</button>
<button type="button" class="toolbar-button">Redo</button>
<span class="toolbar-separator" role="separator" aria-orientation="vertical" />
<button type="button" class="toolbar-button">Cut</button>
<button type="button" class="toolbar-button">Copy</button>
</Toolbar>.toolbar-separator {
inline-size: 1px;
align-self: stretch;
margin-inline: 0.25rem;
background: #d4d4d8;
}Mixed control types
<Toolbar class="toolbar" aria-label="View">
<button type="button" class="toolbar-button">Zoom in</button>
<button type="button" class="toolbar-button">Zoom out</button>
<select class="toolbar-select">
<option>100%</option>
<option>150%</option>
</select>
<a class="toolbar-button" href="/help">Help</a>
</Toolbar>Disabled controls
A control disabled the native way, with disabled on a <button>, drops out of
the focusable set on its own. Navigation skips a Terracotta control marked with
tc-disabled for the same reason.
<Toolbar class="toolbar" aria-label="Editor">
<button type="button" class="toolbar-button">Cut</button>
<button type="button" class="toolbar-button" disabled>Paste</button>
</Toolbar>.toolbar-button:disabled,
.toolbar-button[tc-disabled] {
opacity: 0.4;
cursor: not-allowed;
}State attributes
Toolbar holds no state of its own. The controls inside it do.
| Element | Attribute | Present when |
|---|---|---|
Toolbar |
tc-toolbar |
Always |
Orientation uses the standard aria-orientation attribute instead of a tc-
one, because it is a genuine ARIA property.
Styling
[tc-toolbar] {
display: flex;
gap: 0.25rem;
}
[tc-toolbar][aria-orientation="vertical"] {
flex-direction: column;
}Reading the state in code
Toolbar exposes no state object. Read the state of the controls it contains
instead, such as Toggle's pressed().
Keyboard
| Key | Action |
|---|---|
| → / ← | Next / previous control, when horizontal |
| ↓ / ↑ | Next / previous control, when vertical |
| Home / End | First / last control |
| Tab / Shift+Tab | Enters or leaves the toolbar, which is a single tab stop |
Arrow navigation does not wrap around the ends.
The toolbar uses a roving tabindex:
- The toolbar element itself is not focusable.
- One control has
tabindex="0". Every other control getstabindex="-1". - The control with
tabindex="0"is the one focused last, or the first enabled control if none has been focused yet. - The toolbar keeps this up to date when controls are added, removed or disabled.
Returning to a toolbar puts you back where you left off.
API
<Toolbar>
Renders a <div> by default.
| Prop | Type | Default | Description |
|---|---|---|---|
as |
ValidConstructor |
'div' |
Element or component to render as. |
horizontal |
boolean |
true |
Orientation. Decides which arrow keys navigate and what aria-orientation reports. |
ref |
DynamicNode<T> | (el) => void |
none | Handle to the rendered element. |
children |
JSX.Element |
none | The controls. Not a render prop. |
| …rest | props of as |
none | Forwarded to the rendered element. |
Give the toolbar an accessible name with aria-label or aria-labelledby. Both
are forwarded like any other prop.
Rendered attributes
| Attribute | Value |
|---|---|
role |
"toolbar" |
tabindex |
0 |
aria-orientation |
"horizontal" or "vertical" |
tc-toolbar |
"" |