ComponentsPanel
Toolbar
A bar of buttons, toggles and links that the keyboard reaches as one stop and moves through with the arrows.
Import
import { Toolbar, ToolbarGroup, ToolbarButton, ToolbarOverflowButton, ToolbarLink, ToolbarToggleGroup, ToolbarToggleItem, ToolbarSeparator } from "@booleanpress/ui/toolbar"Usage
A toolbar groups the controls that act on one thing: an editor's formatting, a list's bulk actions. Tab reaches it once; the arrow keys move between its buttons. Use it for three or more controls; two buttons side by side are a button group.
import { BoldIcon, ItalicIcon } from "lucide-react"
import { Toolbar, ToolbarButton } from "@booleanpress/ui/toolbar"
export function Formatting() {
return (
<Toolbar aria-label="Formatting">
<ToolbarButton aria-label="Bold"><BoldIcon /></ToolbarButton>
<ToolbarButton aria-label="Italic"><ItalicIcon /></ToolbarButton>
</Toolbar>
)
}Name the toolbar with aria-label. ToolbarGroup gathers controls: the bar spreads its groups out, so two groups sit at the start and the end, and three at the start, centre and end. ToolbarButton takes Button's variant, size, severity and loading, and defaults to the muted ghost look. ToolbarToggleGroup and ToolbarToggleItem are a toggle group inside the toolbar (type="single" or "multiple"), ToolbarLink a link, and ToolbarSeparator a line between groups. ToolbarOverflowButton is an ellipsis button named by the provider's moreActions string: put it in a dropdown menu's trigger for the actions that do not fit. orientation="vertical" stacks the controls and moves with โ and โ. A field inside the bar, such as a search box, is its own tab stop.
Examples
Basic
An editor's formatting buttons in three groups, with a disabled Redo the arrows skip.
import { BoldIcon, ItalicIcon, LinkIcon, ListIcon, ListOrderedIcon, Redo2Icon, Undo2Icon } from "lucide-react"
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from "@booleanpress/ui/toolbar"
export default function ToolbarBasic() {
return (
<Toolbar aria-label="Email template formatting" className="w-full max-w-xl justify-start">
<ToolbarGroup>
<ToolbarButton aria-label="Undo">
<Undo2Icon />
</ToolbarButton>
<ToolbarButton aria-label="Redo" disabled>
<Redo2Icon />
</ToolbarButton>
</ToolbarGroup>
<ToolbarSeparator />
<ToolbarGroup>
<ToolbarButton aria-label="Bold">
<BoldIcon />
</ToolbarButton>
<ToolbarButton aria-label="Italic">
<ItalicIcon />
</ToolbarButton>
<ToolbarButton aria-label="Insert link">
<LinkIcon />
</ToolbarButton>
</ToolbarGroup>
<ToolbarSeparator />
<ToolbarGroup>
<ToolbarButton aria-label="Bulleted list">
<ListIcon />
</ToolbarButton>
<ToolbarButton aria-label="Numbered list">
<ListOrderedIcon />
</ToolbarButton>
</ToolbarGroup>
</Toolbar>
)
}Start, centre and end
Three groups spread across the bar: icon buttons, a search field and the form's buttons.
import { PlusIcon, PrinterIcon, UploadIcon } from "lucide-react"
import { Input } from "@booleanpress/ui/input"
import { Toolbar, ToolbarButton, ToolbarGroup } from "@booleanpress/ui/toolbar"
export default function ToolbarStartCenterEnd() {
return (
<Toolbar aria-label="Contacts" className="w-full max-w-2xl">
<ToolbarGroup>
<ToolbarButton aria-label="New contact">
<PlusIcon />
</ToolbarButton>
<ToolbarButton aria-label="Print">
<PrinterIcon />
</ToolbarButton>
<ToolbarButton aria-label="Import contacts">
<UploadIcon />
</ToolbarButton>
</ToolbarGroup>
<ToolbarGroup>
<Input aria-label="Search contacts" placeholder="Search" className="w-48" />
</ToolbarGroup>
<ToolbarGroup>
<ToolbarButton variant="outline" size="sm">
Cancel
</ToolbarButton>
<ToolbarButton variant="default" size="sm">
Save
</ToolbarButton>
</ToolbarGroup>
</Toolbar>
)
}With toggle groups
A multiple group for the text style and a single group for the alignment.
import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon, BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react"
import {
Toolbar,
ToolbarButton,
ToolbarSeparator,
ToolbarToggleGroup,
ToolbarToggleItem,
} from "@booleanpress/ui/toolbar"
export default function ToolbarToggleGroups() {
return (
<Toolbar aria-label="Signature formatting" className="w-full max-w-xl justify-start">
<ToolbarToggleGroup type="multiple" aria-label="Text style" defaultValue={["bold"]}>
<ToolbarToggleItem value="bold" aria-label="Bold">
<BoldIcon />
</ToolbarToggleItem>
<ToolbarToggleItem value="italic" aria-label="Italic">
<ItalicIcon />
</ToolbarToggleItem>
<ToolbarToggleItem value="underline" aria-label="Underline">
<UnderlineIcon />
</ToolbarToggleItem>
</ToolbarToggleGroup>
<ToolbarSeparator />
<ToolbarToggleGroup type="single" aria-label="Alignment" defaultValue="left">
<ToolbarToggleItem value="left" aria-label="Align left">
<AlignLeftIcon />
</ToolbarToggleItem>
<ToolbarToggleItem value="center" aria-label="Align centre">
<AlignCenterIcon />
</ToolbarToggleItem>
<ToolbarToggleItem value="right" aria-label="Align right">
<AlignRightIcon />
</ToolbarToggleItem>
</ToolbarToggleGroup>
<ToolbarButton variant="outline" size="sm" className="ms-auto">
Preview
</ToolbarButton>
</Toolbar>
)
}Vertical
orientation="vertical" stacks the buttons; โ and โ move between them.
import { DownloadIcon, FilterIcon, RefreshCwIcon, SettingsIcon } from "lucide-react"
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from "@booleanpress/ui/toolbar"
export default function ToolbarVertical() {
return (
<Toolbar orientation="vertical" aria-label="Delivery log">
<ToolbarGroup>
<ToolbarButton aria-label="Refresh">
<RefreshCwIcon />
</ToolbarButton>
<ToolbarButton aria-label="Filter">
<FilterIcon />
</ToolbarButton>
<ToolbarButton aria-label="Export as CSV">
<DownloadIcon />
</ToolbarButton>
</ToolbarGroup>
<ToolbarSeparator />
<ToolbarButton aria-label="Log settings">
<SettingsIcon />
</ToolbarButton>
</Toolbar>
)
}Overflow menu
A ToolbarOverflowButton at the end opens a dropdown menu of further actions.
Accessibility
- Semantics
- A
divwithrole="toolbar"andaria-orientation. Buttons and links are native; toggle items are buttons witharia-pressed(role="radio"andaria-checkedin asinglegroup); a group isrole="group"; a separator isrole="separator". - Labels
- Name the toolbar (
aria-labeloraria-labelledby) and every icon-only control. The overflow button is named by the provider'smoreActionsstring unless you passaria-label. - Focus
- The toolbar is one tab stop: Tab lands on the last control used (the first at the start), the arrows move from control to control, wrapping at the ends, and Tab leaves. Disabled controls are skipped. Focus is a 1px
--ringoutline 2px outside the control. - Known limits
- A text field inside the toolbar keeps its own arrow keys and is a separate tab stop.
- Groups wrap onto a new line when the bar is narrow; the arrow keys follow the source order.
Keyboard
| Key | Behaviour |
|---|---|
| Tab | Moves into the toolbar, onto the last control used, and out again: one stop. |
| โorโ | Moves to the next or previous control, wrapping at the ends (โ and โ when vertical). Reversed in a right-to-left page. |
| HomeorEnd | Moves to the first or last control. |
| EnterorSpace | Activates the focused button, or toggles the focused toggle item. |
API
Toolbar
Renders Radix Toolbar.Root and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
dir | "ltr" | "rtl" | The reading direction. The provider's dir by default. | |
loop | boolean | Whether the arrows wrap from the last control to the first. true by default. | |
orientation | "horizontal" | "vertical" | horizontal | horizontal (default) or vertical: the layout, and which arrow keys move. |
ToolbarGroup
Renders a div and passes it every other prop.
ToolbarButton
| Prop | Type | Default | Description |
|---|---|---|---|
data-slot | string | toolbar-button | |
loading | boolean | Shows the spinner and sets aria-busy and aria-disabled, as Button's: the button ignores presses but keeps its
focus, and the arrow keys still reach it. | |
raised | boolean | null | Lifts the button on a shadow. | |
rounded | boolean | null | A pill, or a circle for an icon button. | |
severity | "success" | "info" | "warning" | "help" | "danger" | "contrast" | null | Button's severity colour: success, info, warning, help, danger, contrast. | |
size | "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | Button's size: default, xs, sm, lg, or a square icon size. | |
variant | "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | ghost | The button's look, as Button's. ghost by default: muted text that takes the faintest surface on hover. |
ToolbarOverflowButton
| Prop | Type | Default | Description |
|---|---|---|---|
loading | boolean | Shows the spinner and sets aria-busy and aria-disabled, as Button's: the button ignores presses but keeps its
focus, and the arrow keys still reach it. | |
raised | boolean | null | ||
rounded | boolean | null | ||
severity | "success" | "info" | "warning" | "help" | "danger" | "contrast" | null | ||
size | "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | ||
variant | "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | The button's look, as Button's. ghost by default: muted text that takes the faintest surface on hover. |
ToolbarLink
Renders Radix Toolbar.Link and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element (a router's link) instead, with the link's behaviour and classes merged onto it. |
ToolbarToggleGroup
Renders Radix Toolbar.ToggleGroup and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
typerequired | "single" | "multiple" | single (one item on at a time) or multiple. Required. | |
asChild | boolean | ||
defaultValue | string | string[] | The value of the item that is pressed when initially rendered. Use
defaultValue if you do not need to control the state of a toggle group.
The value of the items that are pressed when initially rendered. Use
defaultValue if you do not need to control the state of a toggle group. | |
dir | "ltr" | "rtl" | ||
disabled | boolean | Whether the group is disabled from user interaction. | |
loop | boolean | ||
onValueChange | ((value: string) => void) | ((value: string[]) => void) | The callback that fires when the value of the toggle group changes. The callback that fires when the state of the toggle group changes. | |
orientation | "horizontal" | "vertical" | ||
rovingFocus | boolean | Whether the group should maintain roving focus of its buttons. | |
size | "default" | "sm" | "lg" | null | sm, default or lg, for every item. Defaults to the provider's controlSize. | |
value | string | string[] | The controlled stateful value of the item that is pressed. The controlled stateful value of the items that are pressed. |
ToolbarToggleItem
Renders Radix Toolbar.ToggleItem and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
value | string | string[] | The controlled stateful value of the item that is pressed. The controlled stateful value of the items that are pressed. |
ToolbarSeparator
Renders Radix Toolbar.Separator and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
decorative | boolean | Whether or not the component is purely decorative. When true, accessibility-related attributes are updated so that that the rendered element is removed from the accessibility tree. | |
orientation | "horizontal" | "vertical" | Either vertical or horizontal. Defaults to horizontal. |
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="toolbar" (Toolbar), data-slot="toolbar-group" (ToolbarGroup), data-slot="toolbar-overflow-button" (ToolbarOverflowButton), data-slot="toolbar-link" (ToolbarLink), data-slot="toolbar-toggle-group" (ToolbarToggleGroup), data-slot="toolbar-toggle-item" (ToolbarToggleItem), data-slot="toolbar-separator" (ToolbarSeparator), and data-size.
Provider strings: moreActions (BooleanUIProvider's strings).
Theming
The bar is --card with a 1px --border edge, a 6px radius and 10px padding. Buttons are --muted-foreground on transparent, with --subtle under the pointer; toggle items take the toggle's look; separators are --border; focus is --ring.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--accent-foreground | text |
--border | background |
--card | background |
--card-foreground | text |
--muted-foreground | text |