import { InputGroup, Toolbar } from "@cloudflare/kumo";
import { FunnelSimpleIcon, GearSixIcon, MagnifyingGlassIcon } from "@phosphor-icons/react";

/** Basic Toolbar with an InputGroup and adjacent action buttons. */
export function ToolbarDemo() {
  return (
    <Toolbar className="w-full max-w-md">
      <Toolbar.InputGroup aria-label="Search DNS records" className="flex-1">
        <InputGroup.Addon>
          <MagnifyingGlassIcon />
        </InputGroup.Addon>
        <InputGroup.Input placeholder="Search DNS records" />
      </Toolbar.InputGroup>
      <Toolbar.Button icon={FunnelSimpleIcon} aria-label="Filter" />
      <Toolbar.Button icon={GearSixIcon} aria-label="Settings" />
    </Toolbar>
  );
}

Installation

Barrel

import { Toolbar } from "@cloudflare/kumo";

Granular

import { Toolbar } from "@cloudflare/kumo/components/toolbar";

Usage

Use Toolbar when multiple controls should read as one compact toolbar or filter card. Use Toolbar.Button, Toolbar.Input, and Toolbar.InputGroup to opt supported controls into toolbar sizing, button styling, borders, and radii.

import { InputGroup, Toolbar } from "@cloudflare/kumo";
import { FunnelSimpleIcon, MagnifyingGlassIcon } from "@phosphor-icons/react";

export default function Example() {
  return (
    <Toolbar>
      <Toolbar.InputGroup aria-label="Search DNS records">
        <InputGroup.Addon>
          <MagnifyingGlassIcon />
        </InputGroup.Addon>
        <InputGroup.Input placeholder="Search DNS records" />
      </Toolbar.InputGroup>
      <Toolbar.Button icon={FunnelSimpleIcon} aria-label="Filter" />
    </Toolbar>
  );
}

Behavior

Toolbar item components intentionally own grouped control presentation:

  • Toolbar.Button, Toolbar.Input, and Toolbar.InputGroup inherit the toolbar size.
  • Toolbar.Button always renders with quiet toolbar button styling.
  • Toolbar.InputGroup passes props directly to InputGroup with the toolbar size.
  • Adjacent toolbar items share borders and only the outer corners are rounded.
  • Direct Toolbar children that are not one of the supported toolbar item components do not receive toolbar overrides.

Examples

Input Shorthand

Use Toolbar.Input for simple text inputs that do not need addons.

import { Toolbar } from "@cloudflare/kumo";
import { FunnelSimpleIcon, GearSixIcon } from "@phosphor-icons/react";

/** Toolbar can use the simpler Input shorthand. */
export function ToolbarMixedControlsDemo() {
  return (
    <Toolbar className="w-full max-w-md">
      <Toolbar.Input
        aria-label="Search DNS records"
        placeholder="Search DNS records"
        className="flex-1"
      />
      <Toolbar.Button icon={FunnelSimpleIcon} aria-label="Filter" />
      <Toolbar.Button icon={GearSixIcon} aria-label="Settings" />
    </Toolbar>
  );
}

Input Group

Use Toolbar.InputGroup when one toolbar item needs its own inline addon or suffix.

import { InputGroup, Toolbar } from "@cloudflare/kumo";

/** Toolbar can compose an InputGroup with adjacent actions. */
export function ToolbarInputGroupDemo() {
  return (
    <Toolbar className="w-full max-w-lg">
      <Toolbar.InputGroup aria-label="Worker subdomain" className="flex-1">
        <InputGroup.Input placeholder="my-worker" />
        <InputGroup.Suffix>.workers.dev</InputGroup.Suffix>
      </Toolbar.InputGroup>
      <Toolbar.Button>Visit</Toolbar.Button>
    </Toolbar>
  );
}

Sizes

The size prop supports xs, sm, base, and lg. Every supported toolbar item is locked to the same size.

xs
sm
base
lg
import { Toolbar } from "@cloudflare/kumo";

/** Toolbar locks supported item sizes to the toolbar size. */
export function ToolbarSizesDemo() {
  return (
    <div className="grid gap-3">
      {(["xs", "sm", "base", "lg"] as const).map((size) => (
        <div key={size} className="flex items-center gap-3">
          <span className="w-10 text-sm text-kumo-subtle">{size}</span>
          <Toolbar size={size} className="w-fit">
            <Toolbar.Input aria-label={`${size} search`} placeholder="Search..." />
            <Toolbar.Button>Apply</Toolbar.Button>
          </Toolbar>
        </div>
      ))}
    </div>
  );
}

Button Actions

Toolbar buttons use quiet styling so grouped actions remain visually quiet and consistent.

import { Toolbar } from "@cloudflare/kumo";
import { DownloadSimpleIcon, UploadSimpleIcon } from "@phosphor-icons/react";

/** Toolbar buttons always use quiet toolbar styling. */
export function ToolbarActionsDemo() {
  return (
    <Toolbar>
      <Toolbar.Button icon={UploadSimpleIcon}>Upload</Toolbar.Button>
      <Toolbar.Button icon={DownloadSimpleIcon}>Download</Toolbar.Button>
    </Toolbar>
  );
}

Accessible Labels

Use aria-label for compact toolbar controls that do not have visible labels.

import { Toolbar } from "@cloudflare/kumo";
import { MagnifyingGlassIcon } from "@phosphor-icons/react";

/** Toolbar items use aria-label for compact accessible names. */
export function ToolbarLabelsDemo() {
  return (
    <Toolbar className="w-full max-w-lg">
      <Toolbar.Input aria-label="Search records" className="flex-1" placeholder="Search" />
      <Toolbar.Button icon={MagnifyingGlassIcon} aria-label="Search" />
    </Toolbar>
  );
}

API Reference

PropTypeDefaultDescription
childrenReactNode-Toolbar controls rendered as one grouped card.
size”xs” | “sm” | “base” | “lg""base”Locks every supported toolbar item to this size.
classNamestring-Additional CSS classes merged onto the toolbar root.