Westy Design Systemv0.2.7
OverviewComponentsExamplesStorybook

Foundations

  • Typography
  • Colors
  • Spacing
  • Radius
  • Shadows
  • Icons

Components

  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Avatar
  • Badge
  • Breadcrumb
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Data Table
  • Date Picker
  • Dialog
  • Direction
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Menubar
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Questionnaire
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Sonner
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toggle
  • Toggle Group
  • Tooltip

Chat

  • Attachment
  • Bubble
  • Marker
  • Message
  • Message Scroller

Components

Toggle Group

A set of two-state buttons that can be toggled on or off.

Playground

—type
—variant
—size
—spacing
—orientation
—disabled
Usage
Group ToggleGroupItems under a ToggleGroup and pick a type — "multiple" lets any number of items be on at once. Items inherit variant and size from the group, so set them once at the root. For buttons that perform actions rather than hold state, reach for Button Group instead.
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@workspace/ui/components/toggle-group"

<ToggleGroup type="multiple" aria-label="Text formatting">
  <ToggleGroupItem value="bold" aria-label="Toggle bold">
    <TextBIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="italic" aria-label="Toggle italic">
    <TextItalicIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="underline" aria-label="Toggle underline">
    <TextUnderlineIcon />
  </ToggleGroupItem>
</ToggleGroup>
Single
type="single" keeps at most one item on, like a radio group. Clicking the active item turns it off again, so a selection is not guaranteed — control the value if the group must always have one.
<ToggleGroup type="single" defaultValue="center" aria-label="Text alignment">
  <ToggleGroupItem value="left" aria-label="Align left">
    <TextAlignLeftIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="center" aria-label="Align center">
    <TextAlignCenterIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="right" aria-label="Align right">
    <TextAlignRightIcon />
  </ToggleGroupItem>
</ToggleGroup>
Outline
The outline variant adds an input-colored border and a subtle shadow to each item — use it when the group sits on its own rather than in a toolbar. Items with visible text need no aria-label.
<ToggleGroup type="single" variant="outline" defaultValue="all" aria-label="Call filter">
  <ToggleGroupItem value="all">All</ToggleGroupItem>
  <ToggleGroupItem value="missed">Missed</ToggleGroupItem>
  <ToggleGroupItem value="voicemail">Voicemail</ToggleGroupItem>
</ToggleGroup>
Spacing
The spacing prop sets the gap between items in spacing units — the default is 2 (8px). At spacing={0} the items fuse into a segmented control: inner corners square off, adjacent outline borders collapse, and the group carries one shared shadow.
<ToggleGroup type="single" variant="outline" defaultValue="all" aria-label="Call filter">
  <ToggleGroupItem value="all">All</ToggleGroupItem>
  <ToggleGroupItem value="missed">Missed</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" variant="outline" spacing={0} defaultValue="all" aria-label="Call filter">
  <ToggleGroupItem value="all">All</ToggleGroupItem>
  <ToggleGroupItem value="missed">Missed</ToggleGroupItem>
</ToggleGroup>
Sizes
Three sizes — sm (32px), default (36px) and lg (40px). Set the size on the group and every item follows; the min-width matches the height, so icon-only items stay square.
<ToggleGroup type="multiple" variant="outline" size="sm" aria-label="Text formatting">
  <ToggleGroupItem value="bold" aria-label="Toggle bold">
    <TextBIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="italic" aria-label="Toggle italic">
    <TextItalicIcon />
  </ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="multiple" variant="outline" aria-label="Text formatting">
  ...
</ToggleGroup>
<ToggleGroup type="multiple" variant="outline" size="lg" aria-label="Text formatting">
  ...
</ToggleGroup>
Orientation
orientation="vertical" stacks the items and switches arrow-key navigation to Up and Down. Combined with spacing={0}, corners and borders collapse along the block axis instead.
<ToggleGroup
  type="multiple"
  variant="outline"
  orientation="vertical"
  spacing={0}
  defaultValue={["bold"]}
  aria-label="Text formatting"
>
  <ToggleGroupItem value="bold" aria-label="Toggle bold">
    <TextBIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="italic" aria-label="Toggle italic">
    <TextItalicIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="underline" aria-label="Toggle underline">
    <TextUnderlineIcon />
  </ToggleGroupItem>
</ToggleGroup>
Disabled
Disable the whole group from the root, or pass disabled to a single item to block just that option. Disabled items dim to 50% opacity and keep their pressed state.
<ToggleGroup type="multiple" variant="outline" disabled aria-label="Text formatting">
  <ToggleGroupItem value="bold" aria-label="Toggle bold">
    <TextBIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="italic" aria-label="Toggle italic">
    <TextItalicIcon />
  </ToggleGroupItem>
</ToggleGroup>
RTL
Radix reads direction from the dir prop (or the app-wide DirectionProvider), not from the surrounding markup — a dir="rtl" wrapper alone is not enough. With the prop set, no extra classes are needed: the fused corners use logical properties, and arrow keys follow the reading direction.
<ToggleGroup
  type="single"
  variant="outline"
  spacing={0}
  dir="rtl"
  defaultValue="right"
  aria-label="محاذاة النص"
>
  <ToggleGroupItem value="right" aria-label="محاذاة لليمين">
    <TextAlignRightIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="center" aria-label="توسيط">
    <TextAlignCenterIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="left" aria-label="محاذاة لليسار">
    <TextAlignLeftIcon />
  </ToggleGroupItem>
</ToggleGroup>
Accessibility
The group is a single Tab stop with roving focus — arrow keys move between items and Home/End jump to the edges. type="single" renders a radiogroup of radios; "multiple" renders a toolbar of pressed buttons. Name the group with aria-label and give every icon-only item its own label. Items expose data-state="on|off" for styling and the pressed state to assistive technology.
<ToggleGroup type="multiple" aria-label="Text formatting">
  <ToggleGroupItem value="bold" aria-label="Toggle bold">
    <TextBIcon />
  </ToggleGroupItem>
</ToggleGroup>
API Reference
ToggleGroup wraps the Radix Toggle Group primitive and accepts all of its props — uncontrolled via defaultValue or controlled via value + onValueChange, both typed by type as string or string[]. Items inherit variant, size and spacing from the group context.
ComponentPropDefault
ToggleGrouptype: "single" | "multiple"required
ToggleGroupvariant?: "default" | "outline""default"
ToggleGroupsize?: "default" | "sm" | "lg""default"
ToggleGroupspacing?: number2
ToggleGrouporientation?: "horizontal" | "vertical""horizontal"
ToggleGroupdisabled?: booleanfalse
ToggleGroupItemvalue: stringrequired
<ToggleGroup data-slot="toggle-group" role="radiogroup|toolbar"
  data-variant data-size data-spacing data-orientation />
<ToggleGroupItem data-slot="toggle-group-item" data-state="on|off" />

Tokens used

8 design tokens consumed by the Toggle Group component.

  • --muted

    Muted

    data-[state=on]:bg-mutedhover:bg-muted
  • --foreground

    Foreground

    hover:text-foreground
  • --input

    Input

    border-input
  • --ring

    Ring

    focus-visible:border-ringfocus-visible:ring-ring/50
  • --destructive

    Destructive

    aria-invalid:border-destructivearia-invalid:ring-destructive/20dark:aria-invalid:ring-destructive/40
  • --text-sm

    Text Small (14px)

    text-sm
  • --radius-md

    Radius 0.8× (8px)

    rounded-mdfirst:rounded-s-mdlast:rounded-e-md
  • --spacing

    Spacing unit (4px)

    gap-[--spacing(var(--gap))]h-9min-w-9px-2.5