ComponentsActions

Toggle Group

Toggle buttons that share one value. Use it to pick a layout, a time range, or a theme, or to turn several text styles on at once.

Variants and sizes

default is borderless, outline draws a control border on each item. Items sit 8px apart by default.

Small

28px · split by
default
outline

Default

32px · icon only, one disabled
default
outline

Large

36px · icon and label
default
outline

Segmented controls

spacing={0} joins outline items into one control. Value is controlled and always keeps one choice: pressing the active item again changes nothing.

Usage

Credits in the last 30 days · UTC

Usage by model · Last 30 days
ModelCredits
claude-sonnet-4182.4
gpt-4.1-mini64.15
text-embedding-3-large9.8

Table toolbar

Icon and label items pick the layout. The whole group is disabled while rows load, and the toolbar stacks on narrow widths.

Rows
Order seed traysTo do
Repot the greenhouse basilIn progress
Write the volunteer watering rotationDone

Settings row

A small segmented control as the value of a settings row. This sample keeps the choice in local state.

Preferences

Theme

System follows your device. Saved in this browser.

Sample theme: System

Vertical and multiple

multiple lets several items stay pressed. orientation='vertical' stacks items; Up and Down arrows move focus.

default · spacing 2

Applied: bold, italic

outline · spacing 0

Usage

Toggle group usageTSX
import { ToggleGroup, ToggleGroupItem } from "@tulipfarm/sprout/toggle-group";

const [range, setRange] = useState(30);

<ToggleGroup
  aria-label="Time range"
  variant="outline"
  size="sm"
  spacing={0}
  value={[String(range)]}
  onValueChange={(value) => {
    // Keep one choice: ignore a press that would clear it.
    if (value[0]) setRange(Number(value[0]));
  }}
>
  <ToggleGroupItem value="7">7d</ToggleGroupItem>
  <ToggleGroupItem value="30">30d</ToggleGroupItem>
</ToggleGroup>

<ToggleGroup aria-label="Text style" multiple defaultValue={["bold"]}>
  <ToggleGroupItem value="bold" aria-label="Bold"><Bold /></ToggleGroupItem>
  <ToggleGroupItem value="italic" aria-label="Italic"><Italic /></ToggleGroupItem>
</ToggleGroup>

The value is always an array of item values. Pass value andonValueChange to control it, or defaultValue. Without multiple, pressing an item releases the others, and pressing the active item again sends an empty array. Ignore an empty array, as above, when one choice must stay selected. GiveToggleGroup a type, as in <ToggleGroup<Layout>>, to type the values.

Props

variant is "default" (no border) or "outline" (a control border on each item). size is "sm"(28px, 12px text), "default" (32px), or "lg" (36px). Items inherit both from the group.

spacing is the gap between items in 4px steps and defaults to 2 (8px). spacing={0} joins the items into one segmented control: inner corners are square and outline items share one border. orientation is "horizontal" (default) or "vertical".

disabled on the group disables every item; on an item it disables only that item. Icons are 16px (14px in sm) unless they set their own size. Mark a leading or trailing icon with data-icon="inline-start" or "inline-end" to tighten padding. Both parts take Base UI props such as render, loopFocus, and state functions for className.

Accessibility

The group renders role="group"; name it with aria-label. Each item is a button with aria-pressed. Tab moves into the group once. Left and Right arrows (Up and Down when vertical) move between items and loop at the ends; Home and End jump to the first and last. Space or Enter presses the focused item. Disabled items are skipped. An icon-only item needs its own aria-label.

Color changes take 120ms and stop when reduced motion is requested.

Theme tokens

Pressed items use --sprout-primary-subtle and --sprout-primary, so the TulipFarm theme tints them green. Idle items use --sprout-muted, hover uses --sprout-hover, outline borders use --sprout-input, and the focus ring uses --sprout-focus.