Skip to the content
BooleanPress UI

Form

Toggle group

A row of toggles that share one choice, or several, such as a period or a set of statuses.

Import

import { ToggleGroup, ToggleGroupItem } from "@booleanpress/ui/toggle-group"

Usage

type is required: "single" allows one pressed item at a time, "multiple" any number. Name the group with aria-label, and name icon-only items with aria-label too.

import { ToggleGroup, ToggleGroupItem } from "@booleanpress/ui/toggle-group"

export function Period() {
  return (
    <ToggleGroup type="single" variant="outline" defaultValue="7d" aria-label="Period">
      <ToggleGroupItem value="24h">24 hours</ToggleGroupItem>
      <ToggleGroupItem value="7d">7 days</ToggleGroupItem>
      <ToggleGroupItem value="30d">30 days</ToggleGroupItem>
    </ToggleGroup>
  )
}

With type="single", value is a string and pressing the pressed item clears it to ""; guard in onValueChange when a choice is required. With type="multiple", value is an array of strings. Both are controlled with value and onValueChange, or uncontrolled with defaultValue. variant and size are set once on the group and reach every item. spacing is the gap between items in 4 px steps: 0 (the default) joins the items into one bar; any larger number separates them. For a choice that submits with a form, use RadioGroup.

Examples

Single

One item pressed at a time, as a period filter.

Multiple

Any number of items pressed, as a set of status filters.

Spacing and size

spacing separates the items into their own buttons; size is set on the group.

Disabled

disabled on the group stops every item; on one item it stops that item and the arrow keys skip it.

Accessibility

Semantics
With type="single", the group is role="radiogroup" and each item is role="radio" with aria-checked. With type="multiple", the group is role="group" and each item is a button with aria-pressed.
Labels
Name the group with aria-label or aria-labelledby. Name icon-only items with aria-label.
Focus
The group is one tab stop: Tab goes to the pressed item, or to the first when none is pressed, and the other items are skipped. The arrow keys move focus without changing the value.
Known limits
  • With type="single", an item reads as a radio, yet pressing it again clears the group: unlike a radio group, "nothing chosen" is reachable.
  • Each item is 32 to 40 px high, depending on size, and at least as wide as its text.

Keyboard

Keyboard
KeyBehaviour
TabMoves focus into the group, to the pressed item, or to the first item when none is pressed. A second Tab leaves the group.
ArrowRightArrowDownMoves focus to the next item, wrapping from the last to the first. In right-to-left, ArrowLeft moves forward instead of ArrowRight. It does not change the value.
ArrowLeftArrowUpMoves focus to the previous item, wrapping from the first to the last. In right-to-left, ArrowRight moves back instead of ArrowLeft. It does not change the value.
HomeMoves focus to the first item.
EndMoves focus to the last item.
SpaceEnterPresses the focused item. In a single group it releases the pressed item first; pressing the pressed item clears the group.

API

ToggleGroup

Renders Radix ToggleGroup.Root and passes it every other prop.

ToggleGroup props
PropTypeDefaultDescription
typerequired"single" | "multiple""single" allows one pressed item; "multiple" allows any number. Required.
asChildbooleanRender the child element instead, with this part's behaviour and classes merged onto it.
defaultValuestring | string[]The value of the item that is pressed when initially rendered. Use defaultValue if you do not need to control the state of a toggle group. The value of the items that are pressed when initially rendered. Use defaultValue if you do not need to control the state of a toggle group.
dir"ltr" | "rtl"Reading direction for the arrow keys. Defaults to the provider's.
disabledbooleanWhether the group is disabled from user interaction.
loopbooleanWhether the arrow keys wrap around at the ends. Defaults to true.
onValueChange((value: string) => void) | ((value: string[]) => void)The callback that fires when the value of the toggle group changes. The callback that fires when the state of the toggle group changes.
orientation"horizontal" | "vertical"horizontal or vertical, for the arrow keys. It does not change the layout.
rovingFocusbooleanWhether the group should maintain roving focus of its buttons.
spacingnumber0The gap between items in 4 px steps. 0 joins them into one bar.
valuestring | string[]The controlled stateful value of the item that is pressed. The controlled stateful value of the items that are pressed.

ToggleGroupItem

Renders Radix ToggleGroup.Item and passes it every other prop.

ToggleGroupItem props
PropTypeDefaultDescription
asChildbooleanRender the child element instead, with this part's behaviour and classes merged onto it.
valuestring | string[]The controlled stateful value of the item that is pressed. The controlled stateful value of the items that are pressed.

Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.

Data attributes: data-slot="toggle-group" (ToggleGroup), data-slot="toggle-group-item" (ToggleGroupItem), and data-variant, data-size, data-spacing.

Theming

Items share the toggle's tokens: --accent when pressed, --muted on hover, --input for the outline border. With spacing={0} the outer corners are rounded and the inner ones square, mirrored in right-to-left.

The tokens its classes read. Change their values in your theme, and it follows.

Theme tokens
TokenUsed for