Toolbar
Container for grouping a set of controls — buttons, toggles, links, inputs, separators. Wraps `@base-ui/react/toolbar` for keyboard focus management. Four variants, three sizes, five rounded values, horizontal (with overflow wrap) + vertical orientation, LTR/RTL.
Playground
Installation
pnpm add @tessinaui/uiUsage
import {
Toolbar,
ToolbarButton,
ToolbarGroup,
ToolbarLink,
ToolbarInput,
ToolbarSeparator,
ToolbarSpacer,
} from "@tessinaui/ui";{/* Text editor toolbar — multi-select bold/italic, single-select align */}
function FormatToolbar() {
const [bold, setBold] = useState(true);
const [italic, setItalic] = useState(false);
const [align, setAlign] = useState("left");
return (
<Toolbar aria-label="Format text">
<ToolbarButton iconOnly leadingIcon={<Undo2 />} aria-label="Undo" />
<ToolbarSeparator />
<ToolbarButton iconOnly leadingIcon={<Bold />} aria-label="Bold"
aria-pressed={bold} pressed={bold} onClick={() => setBold((v) => !v)} />
<ToolbarButton iconOnly leadingIcon={<Italic />} aria-label="Italic"
aria-pressed={italic} pressed={italic} onClick={() => setItalic((v) => !v)} />
<ToolbarSeparator />
<ToolbarButton iconOnly leadingIcon={<AlignLeft />} aria-label="Align left"
aria-pressed={align === "left"} pressed={align === "left"} onClick={() => setAlign("left")} />
<ToolbarButton iconOnly leadingIcon={<AlignCenter />} aria-label="Align center"
aria-pressed={align === "center"} pressed={align === "center"} onClick={() => setAlign("center")} />
<ToolbarSpacer />
<ToolbarLink href="/help">Help</ToolbarLink>
</Toolbar>
);
}
{/* Data table action bar */}
<Toolbar variant="outline" aria-label="Table actions">
<ToolbarInput placeholder="Search…" aria-label="Search" />
<ToolbarSeparator />
<ToolbarButton leadingIcon={<Filter />} trailingIcon={<ChevronDown />}>Filter</ToolbarButton>
<ToolbarButton leadingIcon={<ArrowDownUp />} trailingIcon={<ChevronDown />}>Sort</ToolbarButton>
<ToolbarSpacer />
<ToolbarButton leadingIcon={<Plus />}>Add row</ToolbarButton>
</Toolbar>
{/* Vertical media player */}
<Toolbar variant="solid" rounded="full" orientation="vertical">
<ToolbarButton iconOnly leadingIcon={<SkipBack />} aria-label="Previous" />
<ToolbarButton iconOnly leadingIcon={<Play />} aria-label="Play" />
<ToolbarButton iconOnly leadingIcon={<SkipForward />} aria-label="Next" />
</Toolbar>Examples
Default
A basic horizontal toolbar with icon buttons, a separator, and a trailing link.
Variants
Four surface styles — solid, soft, outline, and ghost.
Sizes
Three sizes — sm, md, and lg — affecting padding and item heights.
Vertical
Set orientation="vertical" to stack items in a column.
Pressed
Drive toggle state with the pressed prop — multi-select format buttons and a single-select alignment group.
Action bar
Compose ToolbarInput, ToolbarSpacer, and labelled buttons into a data-table action bar.
Composition
The toolbar is a focus-traversal container — arrow keys move between items, Tab moves to the next focusable region. Compose any focusable primitive inside.
For toggle-style behaviour (bold / italic / underline, alignment groups, pin / favorite), use ToolbarButton with the pressed prop and own the state externally. The pressed appearance uses a tone-aware overlay that reads on every toolbar surface (foreground tint on soft / outline / ghost, background tint on solid). Set aria-pressed for accessibility.
const [bold, setBold] = useState(false);
<ToolbarButton
iconOnly
leadingIcon={<Bold />}
aria-label="Bold"
aria-pressed={bold}
pressed={bold}
onClick={() => setBold((v) => !v)}
/>API Reference
Toolbar (root)
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | Layout direction. Horizontal wraps items to the next row when there isn't enough width. |
variant | "solid" | "soft" | "outline" | "ghost" | "soft" | Surface visual style |
size | "sm" | "md" | "lg" | "md" | Affects padding + item heights. Padding is equal on all sides. |
rounded | "none" | "sm" | "md" | "lg" | "full" | "md" | Container border radius |
loopFocus | boolean | true | Wrap arrow-key focus at the ends |
disabled | boolean | false | Disable all items in the toolbar |
dir | "ltr" | "rtl" | inherited | Text direction |
aria-label | string | — | Recommended; describes the toolbar's purpose |
ToolbarButton
| Prop | Type | Default | Description |
|---|---|---|---|
iconOnly | boolean | false | Square aspect, no horizontal padding |
leadingIcon | ReactNode | — | Icon at the start of the button |
trailingIcon | ReactNode | — | Icon at the end of the button |
pressed | boolean | — | Render in pressed state. Use this for any toggle behaviour — multi-select (bold / italic) or single-select (alignment). Combine with aria-pressed. |
disabled | boolean | false | Disable this single item |
focusableWhenDisabled | boolean | true | Whether the item stays focusable when disabled (Base UI default) |
aria-label | string | — | Required for iconOnly buttons |
ToolbarLink
Same shape as ToolbarButton but renders an <a> element. Pass href and standard anchor attributes.
ToolbarInput
Text input integrated with toolbar focus traversal — arrow keys still navigate the toolbar even when this input is focused.
ToolbarSeparator
Auto-orientation-aware divider:
- Horizontal toolbar → renders as a vertical line (
w-px) - Vertical toolbar → renders as a horizontal line (
h-px) - Color adapts to surface (
bg-current/30on solid,bg-borderotherwise)
ToolbarGroup
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "none" | "contained" | "none" | none = ARIA group only; contained = subtle background tint to visually cluster items |
disabled | boolean | false | Disable all items in the group |
aria-label | string | — | Recommended for any non-trivial group |
ToolbarSpacer
Inserts a flex-1 filler to push following items to the trailing edge — handy for left-aligned tools and right-aligned actions.
Notes
- Variants are neutral —
solid(foreground surface),soft(secondary surface, default),outline(border on background),ghost(transparent). Items use a tone-aware hover overlay (foreground/8on light surfaces,background/15on solid) so hover state is always visible. - Pressed state on
ToolbarButtonworks for any toggle pattern. For a multi-select group (bold / italic / underline), drive each item'spressedfrom its own boolean. For a single-select group (alignment), comparepressed={align === "left"}and update on click. Always pair witharia-pressed. - Padding — equal on all sides (
p-1.5/p-2/p-2.5for sm / md / lg) and matched to the gap between items, so the first/last item has the same breathing room from the toolbar edges as it does from its neighbours. - Horizontal overflow — items wrap to the next row when the toolbar runs out of width (
flex-wrap). Vertical orientation always stacks each item on its own row. - Disabled items stay focusable by default (
focusableWhenDisabled=true) so users can still tab to them and learn what's disabled — this is the Base UI default and matches WAI-ARIA toolbar guidance. - RTL — the toolbar mirrors automatically via
dir="rtl". Arrow-key direction follows the writing direction (right-to-left arrow goes to the next item in RTL). - Accessibility — built on
@base-ui/react/toolbar. Rendersrole="toolbar"witharia-orientation. Always passaria-labelto describe the toolbar's purpose.
ToggleGroup
A pill container of toggle buttons that act like a radio group (single select) or a multi-select toolbar, built on Base UI's ToggleGroup primitive.
Tooltip
Rich tooltip card for product tours, feature walkthroughs, and contextual help. Supports title, image, subtitle, description, keyboard shortcuts, step counter, navigation buttons, a close button, 5 intent colors, 6 rounded variants, and all 12 arrow positions.