Siteplane UI

Toggle Group

Group related pressed-state buttons.

Markdown
"use client";

import {
  AlignCenterIcon,
  AlignJustifyIcon,
  AlignLeftIcon,
  AlignRightIcon,
} from "lucide-react";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  return (
    <ToggleGroup
      aria-label="Text alignment"
      defaultValue={["left"]}
      variant="outline"
    >
      <ToggleGroupItem aria-label="Align left" value="left">
        <AlignLeftIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Align center" value="center">
        <AlignCenterIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Align right" value="right">
        <AlignRightIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Justify" value="justify">
        <AlignJustifyIcon />
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

Installation

pnpm dlx shadcn@4.18.0 add @siteplane/toggle-group

Complete the one-time setup first. Registry JSON lists source files and dependencies.

For this page’s examples, also install:

pnpm dlx shadcn@4.18.0 add @siteplane/input

Field is installed with Input.

Usage

import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

<ToggleGroup aria-label="View" defaultValue={["grid"]}>
  <ToggleGroupItem value="grid">Grid</ToggleGroupItem>
  <ToggleGroupItem value="list">List</ToggleGroupItem>
</ToggleGroup>;

Composition

ToggleGroup
├── ToggleGroupItem
├── ToggleGroupSeparator
└── ToggleGroupItem

Multiple selection

Set multiple to allow several pressed items. value is always an array, in single and multiple mode.

"use client";

import { useState } from "react";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  const [value, setValue] = useState<string[]>(["bold"]);
  return (
    <ToggleGroup
      aria-label="Text formatting"
      multiple
      onValueChange={setValue}
      value={value}
    >
      <ToggleGroupItem value="bold">Bold</ToggleGroupItem>
      <ToggleGroupItem value="italic">Italic</ToggleGroupItem>
      <ToggleGroupItem disabled value="underline">
        Underline
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

With label

Name the group with a visible FieldLabel and point aria-labelledby at it. To keep one option selected, ignore empty values in onValueChange.

"use client";

import { LayoutGridIcon, ListIcon } from "lucide-react";
import { useId, useState } from "react";
import { Field, FieldLabel } from "@/siteplane/components/field";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  const labelId = useId();
  const [view, setView] = useState<string[]>(["grid"]);
  return (
    <Field>
      <FieldLabel id={labelId}>View</FieldLabel>
      <ToggleGroup
        aria-labelledby={labelId}
        onValueChange={(next) => {
          if (next.length > 0) setView(next);
        }}
        value={view}
        variant="outline"
      >
        <ToggleGroupItem value="grid">
          <LayoutGridIcon />
          Grid
        </ToggleGroupItem>
        <ToggleGroupItem value="list">
          <ListIcon />
          List
        </ToggleGroupItem>
      </ToggleGroup>
    </Field>
  );
}

With separators

Place a ToggleGroupSeparator between sets of related items. It is vertical by default; in a vertical group, set orientation="horizontal". Outline groups already draw a divider between every item.

"use client";

import { BoldIcon, ItalicIcon, StrikethroughIcon } from "lucide-react";
import {
  ToggleGroup,
  ToggleGroupItem,
  ToggleGroupSeparator,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  return (
    <ToggleGroup aria-label="Text formatting" defaultValue={["bold"]} multiple>
      <ToggleGroupItem aria-label="Bold" value="bold">
        <BoldIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Italic" value="italic">
        <ItalicIcon />
      </ToggleGroupItem>
      <ToggleGroupSeparator />
      <ToggleGroupItem aria-label="Strikethrough" value="strikethrough">
        <StrikethroughIcon />
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

Vertical

Set orientation="vertical" to stack the items; arrow-key navigation follows the orientation.

"use client";

import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export default function Example() {
  return (
    <ToggleGroup
      aria-label="Text formatting"
      defaultValue={["bold", "italic"]}
      multiple
      orientation="vertical"
    >
      <ToggleGroupItem aria-label="Bold" value="bold">
        <BoldIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Italic" value="italic">
        <ItalicIcon />
      </ToggleGroupItem>
      <ToggleGroupItem aria-label="Underline" value="underline">
        <UnderlineIcon />
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

Sizes

Set size (and variant) on the group; every item inherits it.

"use client";

import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

const sizes = [
  ["sm", "small"],
  ["md", "medium"],
  ["lg", "large"],
  ["xl", "extra large"],
] as const;

export default function Example() {
  return (
    <div className="grid gap-3">
      {sizes.map(([size, name]) => (
        <ToggleGroup
          aria-label={`View, ${name}`}
          defaultValue={["list"]}
          key={size}
          size={size}
        >
          <ToggleGroupItem value="list">List</ToggleGroupItem>
          <ToggleGroupItem value="grid">Grid</ToggleGroupItem>
        </ToggleGroup>
      ))}
    </div>
  );
}

API reference

Component properties
PropTypeDefaultDescription
variantdefault | outlinedefaultItem surface.
sizesm | md | lg | xlprovider / lgItem size.
multiplebooleanfalseAllow multiple pressed items.
orientationhorizontal | verticalhorizontalLayout and keyboard orientation.
widthauto | fullautoFit or full width.
wrapbooleanfalseAllow wrapping.
value / defaultValuestring[]uncontrolledSelection.
onValueChange(values, eventDetails) => voidunsetSelection callback.
ToggleGroupItem.growbooleanfalseFlex-grow item.
ToggleGroupItem.maxWidthlabelunsetCap at max-w-40 and truncate label.
ToggleGroupItem.paddingdefault | comfortabledefaultPadding.
ToggleGroupSeparator.orientationhorizontal | verticalverticalDivider direction.

Items accept Base UI Toggle props including value and disabled and take the group's size and variant. Separator accepts Separator props and draws the divider between joined items. ToggleGroupPrimitive exposes the Base UI namespace. ToggleGroupContext defaults to single false, inherited size and variant default. Other root props and keyboard behavior follow Base UI Toggle Group.

Read the installed source.

Usage notes

Tab enters the group; arrow keys move among items. Unlike RadioGroup, a single selected item can be cleared. Use Tabs for associated content panels.