Skip to main content
Urbicon UI

Toolbar

Action bars for grouping tools, controls, and contextual actions.

Playground

Variant Style variant
Orientation Style variant
Tier (propagated)
<Toolbar
  aria-label="Formatting toolbar"
>
  <Button variant="ghost" size="sm" class="font-bold">B</Button>
  <Button variant="ghost" size="sm" class="italic">I</Button>
  <Button variant="ghost" size="sm" class="underline">U</Button>
  <Separator orientation="vertical" size="sm" />
  <Button variant="ghost" size="sm" aria-label="Align left"><AlignLeftIcon size={16} /></Button>
  <Button variant="ghost" size="sm" aria-label="Align center"
    ><AlignCenterIcon size={16} /></Button
  >
  <Button variant="ghost" size="sm" aria-label="Align right"
    ><AlignRightIcon size={16} /></Button
  >
  <Separator orientation="vertical" size="sm" />
  <Button variant="ghost" size="sm" aria-label="Insert link"><LinkIcon size={16} /></Button>
  <Button variant="ghost" size="sm" aria-label="Insert image"><ImageIcon size={16} /></Button>
</Toolbar>

01 Examples

A Toolbar wraps your own controls (Buttons, Separators, ButtonGroups) and adds role="toolbar" with the required aria-label. It holds no state, so each control drives its own variant and aria-pressed. Group related controls with a vertical Separator, and reach for ButtonGroup instead when the buttons form one connected segmented control.

Rich Text Editor

Drive each button's variant and aria-pressed from your own toggle state. Separators split the bar into formatting, alignment and insert groups.

Click the buttons above to toggle formatting. The text alignment and style update live.

<Toolbar aria-label="Text formatting" gap="xs" padding="sm">
  <Button
    variant={bold ? 'filled' : 'ghost'}
    intent={bold ? 'primary' : 'neutral'}
    size="sm"
    class="min-w-8 justify-center"
    aria-label="Bold"
    aria-pressed={bold}
    onclick={() => (bold = !bold)}><BoldIcon size={16} /></Button
  >
  <Button
    variant={italic ? 'filled' : 'ghost'}
    intent={italic ? 'primary' : 'neutral'}
    size="sm"
    class="min-w-8 justify-center"
    aria-label="Italic"
    aria-pressed={italic}
    onclick={() => (italic = !italic)}><ItalicIcon size={16} /></Button
  >
  <Button
    variant={underline ? 'filled' : 'ghost'}
    intent={underline ? 'primary' : 'neutral'}
    size="sm"
    class="min-w-8 justify-center"
    aria-label="Underline"
    aria-pressed={underline}
    onclick={() => (underline = !underline)}><UnderlineIcon size={16} /></Button
  >
  <Button variant="ghost" size="sm" class="min-w-8 justify-center" aria-label="Strikethrough"
    ><StrikethroughIcon size={16} /></Button
  >

  <Separator orientation="vertical" size="sm" />

  <Button
    variant={alignment === 'left' ? 'filled' : 'ghost'}
    intent={alignment === 'left' ? 'primary' : 'neutral'}
    size="sm"
    class="min-w-8 justify-center"
    aria-label="Align left"
    aria-pressed={alignment === 'left'}
    onclick={() => (alignment = 'left')}><AlignLeftIcon size={16} /></Button
  >
  <Button
    variant={alignment === 'center' ? 'filled' : 'ghost'}
    intent={alignment === 'center' ? 'primary' : 'neutral'}
    size="sm"
    class="min-w-8 justify-center"
    aria-label="Align centre"
    aria-pressed={alignment === 'center'}
    onclick={() => (alignment = 'center')}><AlignCenterIcon size={16} /></Button
  >
  <Button
    variant={alignment === 'right' ? 'filled' : 'ghost'}
    intent={alignment === 'right' ? 'primary' : 'neutral'}
    size="sm"
    class="min-w-8 justify-center"
    aria-label="Align right"
    aria-pressed={alignment === 'right'}
    onclick={() => (alignment = 'right')}><AlignRightIcon size={16} /></Button
  >

  <Separator orientation="vertical" size="sm" />

  <Button variant="ghost" size="sm" class="min-w-8 justify-center" aria-label="Insert link"
    ><LinkIcon size={16} /></Button
  >
  <Button variant="ghost" size="sm" class="min-w-8 justify-center" aria-label="Insert image"
    ><ImageIcon size={16} /></Button
  >
</Toolbar>

<div
  class="bg-surface-base border-border-subtle rounded-contain w-full border p-4 text-sm"
  style="text-align: {alignment};"
>
  <p
    class={[
      'text-text-secondary',
      bold && 'font-bold',
      italic && 'italic',
      underline && 'underline'
    ]}
  >
    Click the buttons above to toggle formatting. The text alignment and style update live.
  </p>
</div>

Vertical Tools Palette

A vertical toolbar whose selected tool drives variant and aria-pressed per button.

Active tool: select

<Toolbar aria-label="Drawing tools" orientation="vertical" variant="elevated" gap="xs">
  {#each [{ id: 'select', icon: MoveIcon, label: 'Select' }, { id: 'pen', icon: EditIcon, label: 'Pen' }, { id: 'brush', icon: HighlighterIcon, label: 'Brush' }, { id: 'undo', icon: UndoIcon, label: 'Undo' }, { id: 'shape', icon: SquareIcon, label: 'Shape' }, { id: 'text', icon: TypeIcon, label: 'Text' }] as tool (tool.id)}
    <Button
      variant={activeTool === tool.id ? 'filled' : 'ghost'}
      intent={activeTool === tool.id ? 'primary' : 'neutral'}
      size="sm"
      class="min-w-9 justify-center"
      onclick={() => (activeTool = tool.id)}
      aria-label={tool.label}
      aria-pressed={activeTool === tool.id}
    >
      <tool.icon size={16} />
    </Button>
  {/each}
</Toolbar>

<div class="bg-surface-base border-border-subtle flex-1 rounded-xl border p-6">
  <p class="text-text-tertiary text-sm">
    Active tool: <Badge size="sm" intent="primary">{activeTool}</Badge>
  </p>
</div>

Media Controls

Playback controls split into groups by vertical Separators.
<Toolbar aria-label="Media player" variant="elevated" gap="sm" padding="md">
  <Button variant="ghost" size="sm" class="justify-center" aria-label="Previous track"
    ><SkipBackIcon size={16} /></Button
  >
  <Button
    variant="filled"
    intent="primary"
    size="sm"
    class="min-w-9 justify-center"
    aria-label="Play"><PlayIcon size={16} /></Button
  >
  <Button variant="ghost" size="sm" class="justify-center" aria-label="Next track"
    ><SkipForwardIcon size={16} /></Button
  >
  <Separator orientation="vertical" size="sm" />
  <Button variant="ghost" size="sm" class="justify-center" aria-label="Shuffle"
    ><ShuffleIcon size={16} /></Button
  >
  <Button variant="ghost" size="sm" class="justify-center" aria-label="Repeat"
    ><RepeatIcon size={16} /></Button
  >
  <Separator orientation="vertical" size="sm" />
  <span class="text-text-tertiary px-2 text-xs tabular-nums">2:34 / 4:12</span>
</Toolbar>

02 Customization

Developer Toolbar

Dark gradient toolbar with accent-colored actions via slotClasses.
<Toolbar
  aria-label="Developer actions"
  variant="ghost"
  slotClasses={{
    base: 'bg-linear-to-r from-neutral-900 to-neutral-800 border border-neutral-700/50 shadow-xl shadow-black/20 rounded-xl px-3 py-2'
  }}
  gap="sm"
>
  <Button
    unstyled
    class="flex items-center gap-1.5 rounded-lg bg-emerald-500/15 px-3 py-1.5 text-xs font-semibold text-emerald-400 transition-colors hover:bg-emerald-500/25"
    ><PlayIcon size={14} /> Run</Button
  >
  <Button
    unstyled
    class="flex items-center gap-1.5 rounded-lg bg-amber-500/15 px-3 py-1.5 text-xs font-semibold text-amber-400 transition-colors hover:bg-amber-500/25"
    ><PauseIcon size={14} /> Debug</Button
  >
  <Separator orientation="vertical" size="sm" />
  <Button
    unstyled
    class="flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium text-neutral-400 transition-colors hover:bg-neutral-700/50 hover:text-neutral-200"
    ><SettingsIcon size={14} /> Settings</Button
  >
  <Button
    unstyled
    class="flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium text-neutral-400 transition-colors hover:bg-neutral-700/50 hover:text-neutral-200"
    ><PackageIcon size={14} /> Build</Button
  >
</Toolbar>

Floating Glass Toolbar

Glassmorphism toolbar floating over a vibrant background, built with unstyled and custom classes.
<Toolbar
  aria-label="Quick actions"
  unstyled
  class="flex items-center gap-2 rounded-2xl border border-white/20 bg-white/10 px-4 py-2.5 shadow-2xl backdrop-blur-xl"
>
  <Button
    unstyled
    class="flex items-center gap-1.5 rounded-xl px-3 py-1.5 text-sm font-medium text-white/90 transition-colors hover:bg-white/15"
    ><SparklesIcon size={15} /> New</Button
  >
  <Button
    unstyled
    class="flex items-center gap-1.5 rounded-xl px-3 py-1.5 text-sm font-medium text-white/90 transition-colors hover:bg-white/15"
    ><FolderOpenIcon size={15} /> Open</Button
  >
  <div class="mx-1 h-5 w-px bg-white/20"></div>
  <Button
    unstyled
    class="flex items-center gap-1.5 rounded-xl bg-white/20 px-3 py-1.5 text-sm font-semibold text-white shadow-lg shadow-black/10 backdrop-blur-sm transition-colors hover:bg-white/30"
    ><SaveIcon size={15} /> Save</Button
  >
</Toolbar>

Pill Toolbar

Fully rounded toolbar with pill-shaped items, using slotClasses for the container.
<Toolbar
  aria-label="Navigation"
  variant="outlined"
  slotClasses={{ base: 'rounded-full px-1.5 py-1 border-border-default' }}
  gap="xs"
>
  <Button variant="filled" intent="primary" size="sm" class="rounded-full">Dashboard</Button>
  <Button variant="ghost" size="sm" class="rounded-full">Projects</Button>
  <Button variant="ghost" size="sm" class="rounded-full">Teams</Button>
  <Button variant="ghost" size="sm" class="rounded-full">Settings</Button>
</Toolbar>

A dock or pill-nav chrome used on several screens belongs in a BlocksProvider preset (presets.Toolbar), applied via preset. See Customization.

03 Accessibility

Built-in ARIA

Renders with role="toolbar". aria-label is required to identify the toolbar's purpose. aria-orientation is set automatically from the orientation prop.

Keyboard

Tab moves focus into and out of the toolbar. Individual items inside the toolbar follow their own keyboard semantics (e.g. Buttons activate via Enter / Space).

Best Practices

Use descriptive aria-label values that communicate the toolbar's function (e.g. "Text formatting", "File actions"). Group related controls using Separator for visual clarity. Avoid nesting toolbars inside each other.

04 API Reference

13 props
13 props 2 required
Prop
Type
Default
Description

05 Types

Local type definitions used by this component.

4 types
Name
Kind
Category
Used by
Description

06 Installation

Import

import { Toolbar, Button, Separator } from '@urbicon-ui/blocks';