Toolbar

Compact action bar for grouping buttons, toggles, and helpers.

Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/toolbar.json
Usage
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?: string
Default
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.
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 refreshactiveAvery
Q4 micrositeactiveJordan
Onboarding rewritepausedSam
Annual reportactiveRiley
Investor deckarchivedCasey
5 total row(s).
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 refreshactiveAvery
Q4 micrositeactiveJordan
Onboarding rewritepausedSam
Annual reportactiveRiley
Investor deckarchivedCasey
5 total row(s).
API Reference
Props for Toolbar and ToolbarItem.

Toolbar

PropTypeDefaultDescription
itemsToolbarItem[]Array of items rendered in order. Drives the entire bar — no compound subcomponents.
orientation"horizontal" | "vertical""horizontal"Layout direction; flips separators and gap axis.
pillbooleanfalseRounded-full container.
floatingbooleanfalseFixed-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`.
visiblebooleantrueWhen `floating`, controls slide-up + fade transition. Toggle from selection state.
zIndexnumber50Stack-context layer when `floating`.
aria-labelstringAccessibility label for the toolbar landmark.

Toolbar button item

PropTypeDefaultDescription
type"button"Discriminator — always `"button"` for action items.
labelReactNodeVisible label. Omit when `iconOnly` is true.
iconLucideIconOptional leading icon component (lucide-react).
iconOnlybooleanfalseSquare 32×32 button. Always pair with `ariaLabel` for accessibility.
variant"ghost" | "primary" | "destructive""ghost"Tone. `primary` = filled Squad violet, `destructive` = red tonal, `ghost` = transparent.
pressedbooleanToggle state. Renders with accented surface and `aria-pressed="true"`.
disabledbooleanDisables the button.
onClick(e) => voidFires when the item is activated.
ariaLabelstringExplicit aria-label (required when `iconOnly`).

ExpandableTabs

PropTypeDefaultDescription
tabsExpandableTab[]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.
valuestring | nullControlled active tab id (`null` = closed). Pair with `onValueChange`.
defaultValuestring | nullnullUncontrolled initial active tab id.
onValueChange(id: string | null) => voidFires 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-labelstring"Navigation tabs"Accessibility label for the tablist.