Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/toolbar.jsonUsage
Group `ToolbarItem`s inside `ToolbarGroup` and divide them with `ToolbarSeparator`.
TSImport
import { Toolbar, type ToolbarItem } from "@/components/ui/toolbar";TSExample
import { LinkIcon, Trash2Icon } from "lucide-react";
import { Toolbar, type ToolbarItem } from "@/components/ui/toolbar";
const items: ToolbarItem[] = [
{ type: "button", icon: LinkIcon, label: "Link" },
{ type: "separator" },
{ type: "button", icon: Trash2Icon, label: "Delete", variant: "destructive" },
];
export function Example() {
return <Toolbar items={items} aria-label="Document actions" />;
}Composition
Anatomy of the Toolbar primitive.
Toolbar (props)
├── items: ToolbarItem[]
│ ├── { type: "button", label?, icon?, iconOnly?, variant?, pressed?, onClick?, ariaLabel?, disabled? }
│ ├── { type: "separator" }
│ ├── { type: "label", content }
│ ├── { type: "spacer" } // pushes the NEXT renderable item to the trailing edge
│ └── { type: "node", content } // arbitrary ReactNode escape hatch
├── orientation?: "horizontal" | "vertical"
├── pill?: boolean // rounded-full ends
├── floating?: boolean // fixed-position floating bar
├── position?: "bottom-center" | "top-center" | "bottom-right" | "bottom-left"
├── visible?: boolean // when floating, drives slide+fade transition
└── aria-label?: string
ExpandableTabs (props) // dynamic-island bar; active tab expands to a labelled pill
├── tabs: ExpandableTab[] // { id, label, icon, content }
│ ├── id: string // stable id (also the active value)
│ ├── label: string // shown in the active pill + a11y name
│ ├── icon: ReactNode // icon node (e.g. <FileTextIcon className="size-4" />)
│ └── content: ReactNode // panel revealed above the bar
├── value? / defaultValue?: string | null // active id (controlled / uncontrolled)
├── onValueChange?: (id | null) => void
├── classNames?: { root, panel, bar, tab, activeTab, icon, label, pill }
└── aria-label?: stringDefault
Mixed buttons grouped with separators. Drop an `items` array; the renderer handles spacing and dividers.
Pill
Pass `pill` for rounded-full ends. Good for floating contextual toolbars (Notion-style block menus, image hovers).
Toggle items
Pass `pressed` on a button item to render an active toggle state with `aria-pressed`. Drive it with local state for one-of-many groups or boolean toggles.
Expandable tabs
A dynamic-island icon bar: the active tab expands into a labelled pill while the whole shell animates its width/height open to reveal that tab's `content` panel above the bar; content cross-fades on switch. Pass a `tabs` array of `{ id, label, icon, content }`; single-select, and clicking the active tab again closes it.
BriefChecklistNotesCalendarAlerts
Inline bulk-action toolbar
Wire `<DataGrid onSelectionChange>` to local state, then render the toolbar above the table when the selection set is non-empty. The `clear` button re-mounts the grid via `key` to reset internal selection.
| Brand refresh | active | Avery | |
| Q4 microsite | active | Jordan | |
| Onboarding rewrite | paused | Sam | |
| Annual report | active | Riley | |
| Investor deck | archived | Casey |
5 total row(s).
Rows per page
Floating bulk-action toolbar
Pass `floating` for a fixed-position bar that anchors to `bottom-center` of the viewport (overridable via `position`). Drive `visible` from selection state to slide it in and out with a built-in transition.
Select one or more rows — a floating bulk-action toolbar slides up from the bottom of the viewport.
| Brand refresh | active | Avery | |
| Q4 microsite | active | Jordan | |
| Onboarding rewrite | paused | Sam | |
| Annual report | active | Riley | |
| Investor deck | archived | Casey |
5 total row(s).
Rows per page
0 selected
API Reference
Props for Toolbar and ToolbarItem.
Toolbar
| Prop | Type | Default | Description |
|---|---|---|---|
items | ToolbarItem[] | — | Array of items rendered in order. Drives the entire bar — no compound subcomponents. |
orientation | "horizontal" | "vertical" | "horizontal" | Layout direction; flips separators and gap axis. |
pill | boolean | false | Rounded-full container. |
floating | boolean | false | Fixed-position floating bar with safe-area padding. Defaults to bottom-center. |
position | "bottom-center" | "top-center" | "bottom-right" | "bottom-left" | "bottom-center" | Anchor point when `floating`. |
visible | boolean | true | When `floating`, controls slide-up + fade transition. Toggle from selection state. |
zIndex | number | 50 | Stack-context layer when `floating`. |
aria-label | string | — | Accessibility label for the toolbar landmark. |
Toolbar button item
| Prop | Type | Default | Description |
|---|---|---|---|
type | "button" | — | Discriminator — always `"button"` for action items. |
label | ReactNode | — | Visible label. Omit when `iconOnly` is true. |
icon | LucideIcon | — | Optional leading icon component (lucide-react). |
iconOnly | boolean | false | Square 32×32 button. Always pair with `ariaLabel` for accessibility. |
variant | "ghost" | "primary" | "destructive" | "ghost" | Tone. `primary` = filled Squad violet, `destructive` = red tonal, `ghost` = transparent. |
pressed | boolean | — | Toggle state. Renders with accented surface and `aria-pressed="true"`. |
disabled | boolean | — | Disables the button. |
onClick | (e) => void | — | Fires when the item is activated. |
ariaLabel | string | — | Explicit aria-label (required when `iconOnly`). |
ExpandableTabs
| Prop | Type | Default | Description |
|---|---|---|---|
tabs | ExpandableTab[] | — | Tabs in order. Each is `{ id, label, icon, content }` — `label` shows in the active pill, `icon` is a node, and `content` is the panel revealed above the bar. |
value | string | null | — | Controlled active tab id (`null` = closed). Pair with `onValueChange`. |
defaultValue | string | null | null | Uncontrolled initial active tab id. |
onValueChange | (id: string | null) => void | — | Fires with the new active id (or `null` when closed). |
classNames | { root, panel, bar, tab, activeTab, icon, label, pill } | — | Per-slot className overrides for fine-grained styling. |
aria-label | string | "Navigation tabs" | Accessibility label for the tablist. |