Toolbar
ProA row (or column) of controls that is one tab stop: the arrow keys move between its buttons, links and fields, swapped in a right-to-left page, and Home and End jump to the first and the last. A control that can't be used now goes inside Locked with its reason and stays in the arrow order, focusable, so a keyboard user reaches it and hears why.
Its parts are ToolbarGroup (a named set), ToolbarButton, ToolbarLink, ToolbarInput, ToolbarSeparator and ToolbarSpacer, which pushes what follows it to the far end: put the actions that belong at the start in a group before it, and the rest in one after it.
For an artifact's maximise, download and ask actions use ArtifactToolbar, and a data table keeps its own toolbar; Toolbar is for any other set of actions over a document, a canvas or a list.
Version 5.2.0· other versions
This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).
Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1, 2.6.2, 2.7.0, 2.8.0, 2.9.0, 2.10.0, 3.0.0, 4.0.0, 4.0.1, 4.0.2, 4.1.0 and 4.2.0: the page came later, or had another name then.
Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.
Preview
Loading the preview
Install
First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/toolbar
Brings in: button, locale, motion, tokens, use-announcer, utils · npm: @base-ui/react@^1.9.0, class-variance-authority@^0.7.1
Usage
"use client"
import * as React from "react"
import { AlignCenter, AlignLeft, Bold, Italic, MessageSquare, Share2, Underline } from "lucide-react"
import { Locked } from "@/components/candor/locked"
import { TooltipProvider } from "@/components/candor/ui/tooltip"
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarInput, ToolbarLink, ToolbarSeparator, ToolbarSpacer } from "@/components/candor/ui/toolbar"
export default function Example() {
const [last, setLast] = React.useState("Nothing yet.")
// The app's selection: the "Selection" group shows only while there is one, and is announced when it appears.
const [selected, setSelected] = React.useState(false)
return (
<TooltipProvider>
<div className="flex max-w-2xl flex-col gap-2 rounded-xl border bg-card p-2">
<Toolbar label="Formatting">
<ToolbarGroup label="Text style">
<ToolbarButton size="icon-sm" aria-label="Bold" onClick={() => setLast("Bold")}>
<Bold aria-hidden />
</ToolbarButton>
<ToolbarButton size="icon-sm" aria-label="Italic" onClick={() => setLast("Italic")}>
<Italic aria-hidden />
</ToolbarButton>
<Locked reason="Underline is off in shared notes.">
<ToolbarButton size="icon-sm" aria-label="Underline">
<Underline aria-hidden />
</ToolbarButton>
</Locked>
</ToolbarGroup>
<ToolbarSeparator />
<ToolbarGroup label="Alignment">
<ToolbarButton size="icon-sm" aria-label="Align left" onClick={() => setLast("Align left")}>
<AlignLeft aria-hidden />
</ToolbarButton>
<ToolbarButton size="icon-sm" aria-label="Align centre" onClick={() => setLast("Align centre")}>
<AlignCenter aria-hidden />
</ToolbarButton>
</ToolbarGroup>
{selected ? (
<>
<ToolbarSeparator />
<ToolbarGroup label="Selection" reveal>
<ToolbarButton onClick={() => setLast("Comment")}>
<MessageSquare aria-hidden />
Comment
</ToolbarButton>
</ToolbarGroup>
</>
) : null}
<ToolbarSpacer />
<ToolbarGroup label="Document">
<ToolbarInput label="Find in note" placeholder="Find" />
<ToolbarLink href="#toolbar">Help</ToolbarLink>
<ToolbarButton onClick={() => setLast("Share")}>
<Share2 aria-hidden />
Share
</ToolbarButton>
</ToolbarGroup>
</Toolbar>
<label className="flex items-center gap-1.5 px-2 text-xs text-muted-foreground">
<input type="checkbox" checked={selected} onChange={(e) => setSelected(e.target.checked)} />
Text is selected
</label>
<p className="px-2 text-xs text-muted-foreground">{last}</p>
</div>
</TooltipProvider>
)
}<Toolbar>
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | — | The toolbar's accessible name ("Formatting", "Actions for Q3 report"). Required: a toolbar without one is a row of buttons with no name. |
| orientation | "horizontal" | "vertical" | undefined | "horizontal" | Which way it runs: "horizontal" (the default, Left and Right move) or "vertical" (Up and Down move). |
| loopFocus | boolean | undefined | true | Whether an arrow key at the last control wraps to the first, and back. On by default. |
| className | string | undefined | — | Classes for the root, merged with Candor's. |
| children | React.ReactNode | undefined | — | The parts: groups, buttons, links, fields, separators and a spacer. |
Also takes the props of Omit<ToolbarPrimitive.Root.Props, "className" | "render" | "aria-label" | "orientation" | "loopFocus">.
<ToolbarButton>
A button in a Toolbar, a ghost Button by default. Name it in aria-label when it shows only an icon. To lock it, wrap it in Locked with the reason: it stays in the arrow order.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | VariantProps<typeof buttonVariants>["variant"] | undefined | "ghost" | The button's look, as `Button`'s: "ghost" by default. |
| size | VariantProps<typeof buttonVariants>["size"] | undefined | "sm" | The button's size, as `Button`'s: "sm" by default; "icon-sm" for an icon alone. |
| className | string | undefined | — | Classes for the button, merged with Candor's. |
Also takes the props of Omit<ToolbarPrimitive.Button.Props, "className" | "render">.
<ToolbarGroup>
A named set of controls inside a Toolbar ("Text style", "Alignment"), read as one group by screen readers.
Set reveal on a group the app shows only sometimes, such as the actions for a selection: when it appears after the toolbar first drew, it fades in and screen readers hear once how many actions it brought ("3 actions available"). Render it only while it applies; one there at the first draw is still and quiet. When it goes with focus in it, focus moves to the toolbar's first control.
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | undefined | — | The group's accessible name. Without one it is still a group, unnamed. |
| reveal | boolean | undefined | false | The group appears and goes with what it acts on (a selection): it fades in and is announced once when it appears. |
| className | string | undefined | — | Classes for the group, merged with Candor's. |
Also takes the props of Omit<ToolbarPrimitive.Group.Props, "className" | "render">.
<ToolbarInput>
A text field in a Toolbar. The arrow keys move the caret inside it, and leave it for the next control only from its first or last character, so typing is never cut short.
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | — | The field's accessible name. A placeholder isn't one, so it is required. |
| className | string | undefined | — | Classes for the field, merged with Candor's. |
Also takes the props of Omit<ToolbarPrimitive.Input.Props, "className" | "render" | "aria-label">.
<ToolbarLink>
A link in a Toolbar, drawn as a ghost button, reached with the same arrow keys as the buttons beside it.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | undefined | — | Classes for the link, merged with Candor's. |
Also takes the props of Omit<ToolbarPrimitive.Link.Props, "className">.
<ToolbarSeparator>
A line between two sets of controls in a Toolbar, across its direction; screen readers hear it as a separator. It is a border, so it stays drawn in forced colours.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | undefined | — | Classes for the line, merged with Candor's. |
Also takes the props of Omit<ToolbarPrimitive.Separator.Props, "className" | "render">.
<ToolbarSpacer>
Empty space that pushes the controls after it to the toolbar's far end (the inline end, or the bottom when vertical).
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | undefined | — | Classes for the space, merged with Candor's. |
Strings
The fixed words, in English by default. Change any of them under toolbar in <LocaleProvider strings={{ … }}>; the table is exported as toolbarStrings.
| Key | English |
|---|---|
| revealed | { one: "{count} action available", other: "{count} actions available" } |
Motion
| Moment | Family | What it does |
|---|---|---|
| group | reveal, fade | A `reveal` group fades in when it appears after the toolbar first drew. |
Set with --cd-motion-toolbar-<moment>-* in your brand file; the families are in the design reference.