Toolbar
Frequent task actions in one named composite, with actual effects and discoverable unavailable controls.
Choose direct task actions
Use a toolbar for several frequent controls acting on the current task. A command bar with menus is a menubar; site destinations belong in navigation. A toolbar reduces repeated Tab stops while arrows explore controls.
Use meaningful labels rather than unexplained letters. Icon actions need useful names and discoverable explanations. Toggle actions expose aria-pressed and change actual state; ordinary commands should not pretend to be toggles.
- Provide a task-specific toolbar name and subgroup labels when grouping matters.
- Avoid controls whose arrow-key operation conflicts with toolbar navigation. Complex composition needs its own interaction design and tests.
- A disabled control may remain arrow-focusable for discovery. Explain unavailability and reject activation independently from focusability.
Anatomy, specifications and variants
| Part | Actual contract |
|---|---|
| Toolbar | Default div with toolbar role; horizontal wrapping flex, 4px gap/padding, 2px border and medium radius. Vertical orientation makes a column. |
| ToolbarButton | Default button, minimum 44px target and 8px padding. Muted hover fill and independent 2px inset keyboard outline. |
| Pressed state | Caller-owned aria-pressed drives actual setting and foreground/background pressed treatment. ToolbarButton is not automatically a toggle. |
| ToolbarGroup | Groups controls and can disable contained buttons. Orientation follows root; installed primitive supplies grouping semantics. |
| ToolbarSeparator | Presentation division perpendicular to toolbar direction: 1px line with 4px margin. No action name. |
| ToolbarLink | Default anchor; underlined foreground text and minimum 44px target. Real href supplies destination behavior. Root disabled does not disable links. |
| Adaptive / alternate modes | Narrow horizontal controls wrap in DOM order. Prefer fewer actions/verified menu when labels dominate. Reduced-motion/forced-color rules are supplied. |
Material docked and floating toolbar choices
The expressive docked toolbar replaces the native baseline bottom app bar recommendation; floating toolbars add contextual horizontal/vertical placement and optional separately composed FABs. Standard surface colors keep attention on content; vibrant roles or one emphasized action increase control emphasis. These are native layout/visual variants, not additional props of this web Toolbar composite.
| Reference decision | Local web contract and application choice |
|---|---|
| Dimensions and shape | Native defaults include 64dp height,16dp outside padding/margin (24dp for vertical floating placement),48dp targets and configurable item spacing. Native docked corners are normally straight, but later web/large-screen guidance permits rounding and other placement. The local wrapping border/radius/gap and 44px controls are the actual contract; avoid claiming a native fixed bottom surface. |
| Hierarchy and navigation | Avoid two competing controls occupying the same bottom navigation space. A document sidebar plus a local command toolbar is a different relationship. Keep site destinations as links/navigation, tab categories as Tabs and command composites as Toolbar. One primary action/FAB is clearer than several competing emphasized controls. |
| Slots and overflow | Toolbar slots can contain actions or text inputs, but each keeps its semantic and keyboard contract. This fixture supplies formatting, duplication, an unavailable command and a context link. Extra actions can use an actually implemented Menu composition; no automatic overflow menu or keyboard shortcut manager is exported. |
| Responsive and floating placement | Native floating surfaces stay within their pane, with essential actions visible and trailing overflow when needed. Vertical floating is generally unsuitable for complex compact layouts, and larger layouts may place it opposite a rail. This lab demonstrates live orientation and direction in flow, without covering content or advertising FAB-collapse physics. |
| Container and keyboard | Native mobile containers may be generic and have no independent interactions; web uses toolbar. The installed primitive is a roving-focus composite with its pinned arrow, disabled-discovery and link behavior, rather than a role added to a div of ordinary Tab buttons. Embedded editing controls must preserve their own input keys when composed. |
| Scrolling and lifecycle | Native choices stay, hide or collapse on scroll; do not collapse and move offscreen together. The local toolbar remains in document flow. A product adding sticky/floating behavior must preserve all commands, focus and recovery during scrolling/resizing and mirror only directional meaning in RTL. |
Working commands and context
Bold and Italic change sample style; Duplicate changes the actual local count. Unavailable publish is wired to a detectable invalid outcome but must reject activation. Change orientation/direction/disabled focusability to inspect behavior. The context link remains a real destination while buttons are disabled.
English-only local sample. Local copies: 0.
The toolbar changes local presentation and copy count. Its context link remains a real destination even while buttons are disabled. No remote write or language review occurs.
Local emphasis: regular, upright. Local copies: 0.
'use client';
import { useState } from 'react';
import { Button, DirectionProvider, Toolbar, ToolbarButton, ToolbarGroup, ToolbarLink, ToolbarSeparator } from '@mobtranslate/ui';
export function NavigationToolbarExample() {
const [bold, setBold] = useState(false);
const [italic, setItalic] = useState(false);
const [copies, setCopies] = useState(0);
const [vertical, setVertical] = useState(false);
const [rtl, setRtl] = useState(false);
const [disabled, setDisabled] = useState(false);
const [skipDisabled, setSkipDisabled] = useState(false);
const direction = rtl ? 'rtl' : 'ltr';
return <div data-toolbar-lab className="space-y-4">
<p data-toolbar-sample style={{fontWeight: bold ? 700 : 400, fontStyle: italic ? 'italic' : 'normal'}}>English-only local sample. Local copies: {copies}.</p>
<div className="flex flex-wrap gap-3">
<Button type="button" variant="outline" aria-pressed={vertical} onClick={() => setVertical(current => !current)}>Use vertical local toolbar</Button>
<Button type="button" variant="outline" aria-pressed={rtl} onClick={() => setRtl(current => !current)}>Use RTL local toolbar</Button>
<Button type="button" variant="outline" aria-pressed={disabled} onClick={() => setDisabled(current => !current)}>Disable local toolbar buttons</Button>
<Button type="button" variant="outline" aria-pressed={skipDisabled} onClick={() => setSkipDisabled(current => !current)}>Skip unavailable toolbar action</Button>
</div>
<DirectionProvider direction={direction}><div dir={direction}>
<Toolbar aria-label="Local sample actions" orientation={vertical ? 'vertical' : 'horizontal'} disabled={disabled} className={state => state.disabled ? 'local-toolbar-disabled' : undefined}>
<ToolbarGroup aria-label="Local text emphasis">
<ToolbarButton type="button" aria-pressed={bold} onClick={() => setBold(current => !current)}>Bold local text</ToolbarButton>
<ToolbarButton type="button" aria-pressed={italic} onClick={() => setItalic(current => !current)}>Italic local text</ToolbarButton>
</ToolbarGroup>
<ToolbarSeparator />
<ToolbarButton type="button" onClick={() => setCopies(current => current + 1)}>Duplicate local sample</ToolbarButton>
<ToolbarButton type="button" disabled focusableWhenDisabled={!skipDisabled} onClick={() => setCopies(-999)}>Remote publish unavailable</ToolbarButton>
<ToolbarLink href="#toolbar-task-context">Read local task context</ToolbarLink>
</Toolbar>
</div></DirectionProvider>
<p id="toolbar-task-context" tabIndex={-1}>The toolbar changes local presentation and copy count. Its context link remains a real destination even while buttons are disabled. No remote write or language review occurs.</p>
<Button type="button" variant="outline" onClick={() => { setBold(false); setItalic(false); setCopies(0); setDisabled(false); }}>Restore local toolbar sample</Button>
<p role="status">Local emphasis: {bold ? 'bold' : 'regular'}, {italic ? 'italic' : 'upright'}. Local copies: {copies}.</p>
</div>;
}
API reference for the installed version
| Export / prop | Installed rc.0 contract |
|---|---|
| Toolbar orientation / loopFocus | horizontal / true defaults. Orientation changes navigation and geometry; false loopFocus stops at ends. |
| Toolbar disabled | Disables contained toolbar buttons. Real ToolbarLink destinations remain available; guard/hide unavailable destinations explicitly. |
| ToolbarButton disabled / focusableWhenDisabled | false / true defaults. Disabled action can remain arrow-discoverable while rejecting activation; false skips it. |
| ToolbarButton type / nativeButton / render | Default button; specify type="button" for commands in forms. Preserve installed handlers/refs when composing a trigger/custom button. |
| ToolbarButton aria-pressed / onClick | Caller-owned setting/action. Change actual value and content; CSS data-pressed alone does not establish semantics. |
| ToolbarGroup disabled | Disables group buttons; neither an authorization gate nor a native fieldset. |
| ToolbarLink href / native anchor props | Anchor/href with installed composite focus integration. No disabled prop. |
| ToolbarSeparator | Installed perpendicular separator orientation. Put meaningful labels on groups, not separators. |
| className / style / render / native props | Installed state callbacks are preserved. Custom rendered elements must retain supplied roles, handlers, attributes and refs. Check actual DOM and keyboard behavior after composition. |
Keyboard and alternate input
- Tab/Shift+Tab enters and leaves the composite. Arrows follow orientation/DirectionProvider. Test live direction changes before the next key.
- The installed Toolbar does not enable Home/End; use arrows and verify loopFocus wrapping. Do not assume disabled controls are skipped: this version defaults focusableWhenDisabled to true.
- Enter/Space performs button actions. Unavailable controls reject pointer/keyboard activation; links retain native destination behavior.
- Wrapped toolbars retain one-dimensional DOM order; do not imply row/column navigation.
- Text labels work for touch and keyboard. Tooltips alone are insufficient names. Shortcuts require a documented task boundary and are not supplied here.
State, recovery and composition
| State / failure | Response |
|---|---|
| Rest / pressed | Actual formatting/count is authoritative; aria-pressed and visual cue reflect the same value. |
| Unavailable | Readable reason, rejected callbacks and explicit discoverability choice. |
| Root disabled | Explain unavailable buttons and retain independent recovery. Links remain destinations; no whole-subtree disable claim. |
| Pending remote command | Guard duplicate requests, retain task state and show cancel/outcome/retry outside disappearing controls. This lab runs no remote command. |
| Restore | Reset actual styles/count and re-enable controls with an independent button. No destructive data action occurs. |
| Custom rendering | Retain ref, native semantics, composite focus and merged handlers. A generic child with toolbar role is insufficient. |
| Navigation confusion | Do not use toolbar/menubar roles for site destinations. Use named nav, real links and current-page state. |
Verification and release scope
- Check actual values/content, names, roles, relations, focus order and unavailable activation with pointer and keyboard. Change callbacks alone do not prove a working task.
- Test 320px reflow, long labels, both themes, text spacing/zoom, live orientation/RTL, reduced motion and forced colors. Hardware touch and spoken announcements need their own device/browser evidence.
- Run test:navigation-controls, source/token freshness, lint, typechecks, production build and route checks. Family tests are scoped evidence, not whole-library accessibility certification.
- English-only examples use local page state. They establish no persistent save, source authority, consent, cultural permission, language correctness or remote review.