Toggle Group
A toggle group lets users toggle one or more related options.
Features
- Fully managed keyboard navigation
- Supports horizontal and vertical orientation
- Supports multiple selection
Installation
Install the toggle group package:
npm install @zag-js/toggle-group @zag-js/react # or yarn add @zag-js/toggle-group @zag-js/react
npm install @zag-js/toggle-group @zag-js/solid # or yarn add @zag-js/toggle-group @zag-js/solid
npm install @zag-js/toggle-group @zag-js/vue # or yarn add @zag-js/toggle-group @zag-js/vue
npm install @zag-js/toggle-group @zag-js/svelte # or yarn add @zag-js/toggle-group @zag-js/svelte
Anatomy
To set up the toggle group correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
Import the toggle group package:
import * as toggle from "@zag-js/toggle-group"
The toggle group package exports two key functions:
machine- State machine logic.connect- Maps machine state to JSX props and event handlers.
Then use the framework integration helpers:
import { normalizeProps, useMachine } from "@zag-js/react" import * as toggle from "@zag-js/toggle-group" import { useId } from "react" export function ToggleGroup() { const service = useMachine(toggle.machine, { id: useId() }) const api = toggle.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <button {...api.getItemProps({ value: "bold" })}>B</button> <button {...api.getItemProps({ value: "italic" })}>I</button> <button {...api.getItemProps({ value: "underline" })}>U</button> </div> ) }
import { normalizeProps, useMachine } from "@zag-js/solid" import * as toggle from "@zag-js/toggle-group" import { createMemo, createUniqueId } from "solid-js" export function ToggleGroup() { const service = useMachine(toggle.machine, { id: createUniqueId() }) const api = createMemo(() => toggle.connect(service, normalizeProps)) return ( <div {...api().getRootProps()}> <button {...api().getItemProps({ value: "bold" })}>B</button> <button {...api().getItemProps({ value: "italic" })}>I</button> <button {...api().getItemProps({ value: "underline" })}>U</button> </div> ) }
<script setup> import * as toggle from "@zag-js/toggle-group" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const service = useMachine(toggle.machine, { id: "1" }) const api = computed(() => toggle.connect(service, normalizeProps)) </script> <template> <div v-bind="api.getRootProps()"> <button v-bind="api.getItemProps({ value: 'bold' })">B</button> <button v-bind="api.getItemProps({ value: 'italic' })">I</button> <button v-bind="api.getItemProps({ value: 'underline' })">U</button> </div> </template>
<script lang="ts"> import { normalizeProps, useMachine } from "@zag-js/svelte" import * as toggle from "@zag-js/toggle-group" const id = $props.id() const service = useMachine(toggle.machine, { id }) const api = $derived(toggle.connect(service, normalizeProps)) </script> <div {...api.getRootProps()}> <button {...api.getItemProps({ value: "bold" })}>B</button> <button {...api.getItemProps({ value: "italic" })}>I</button> <button {...api.getItemProps({ value: "underline" })}>U</button> </div>
Changing the orientation
By default, the toggle group is assumed to be horizontal. To change the
orientation to vertical, set the orientation property in the machine's context
to vertical.
const service = useMachine(toggle.machine, { orientation: "vertical", })
Listening for value changes
When the pressed toggle in the group changes, onValueChange callback is
invoked.
const service = useMachine(toggle.machine, { onValueChange(details) { // details => { value: string[] } console.log(details.value) }, })
Controlled toggle group
Use value and onValueChange for controlled usage.
const service = useMachine(toggle.machine, { value, onValueChange(details) { setValue(details.value) }, })
Allowing multiple selection
Set the multiple property in the machine's context to true to allow multiple
options to be toggled.
const service = useMachine(toggle.machine, { multiple: true, })
Disabling the toggle group
Set the disabled property in the machine's context to true to disable the
toggle group.
const service = useMachine(toggle.machine, { disabled: true, })
Disabling a toggle
Set the disabled property in getItemProps to true to disable a toggle.
//... <div {...api.getRootProps()}> <button {...api.getItemProps({ value: "bold", disabled: true })}>B</button> </div> //...
Disabling focus loop
The toggle group loops keyboard navigation by default. To disable this, set the
loopFocus property in the machine's context to false.
const service = useMachine(toggle.machine, { loopFocus: false, })
Disabling roving focus management
The toggle group uses roving focus management by default. To disable this, set
the rovingFocus property in the machine's context to false.
const service = useMachine(toggle.machine, { rovingFocus: false, })
Allowing or preventing deselection
Use deselectable to control whether the active item can be toggled off in
single-select mode.
const service = useMachine(toggle.machine, { deselectable: false, })
Programmatic value control
Use the API for imperative updates.
api.setValue(["bold", "italic"])
Styling Guide
Each part includes a data-part attribute you can target in CSS.
Pressed State
The toggle is pressed, the data-state attribute is applied to the toggle
button with on or off values.
[data-part="item"][data-state="on|off"] { /* styles for toggle button */ }
Focused State
When a toggle button is focused, the data-focus is applied to the root and
matching toggle button.
[data-part="root"][data-focus] { /* styles for the root */ } [data-part="item"][data-focus] { /* styles for the toggle */ }
Disabled State
When a toggle button is disabled, the data-disabled is applied to the root and
matching toggle button.
[data-part="root"][data-disabled] { /* styles for the root */ } [data-part="item"][data-disabled] { /* styles for the toggle */ }
Methods and Properties
Machine Context
The toggle group machine exposes the following context properties:
idsPartial<{ root: string; item: (value: string) => string; }>The ids of the elements in the toggle. Useful for composition.disabledbooleanWhether the toggle is disabled.valuestring[]The controlled selected value of the toggle group.defaultValuestring[]The initial selected value of the toggle group when rendered. Use when you don't need to control the selected value of the toggle group.onValueChange(details: ValueChangeDetails) => voidFunction to call when the toggle is clicked.loopFocusbooleanWhether to loop focus inside the toggle group.rovingFocusbooleanWhether to use roving tab index to manage focus.orientationOrientationThe orientation of the toggle group.multiplebooleanWhether to allow multiple toggles to be selected.deselectablebooleanWhether the toggle group allows empty selection. **Note:** This is ignored if `multiple` is `true`.dir"ltr" | "rtl"The document's text/writing direction.idstringThe unique identifier of the machine.getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The toggle group api exposes the following methods:
valuestring[]The value of the toggle group.setValue(value: string[]) => voidSets the value of the toggle group.getItemState(props: ItemProps) => ItemStateReturns the state of the toggle item.
Data Attributes
Accessibility
Uses roving tabindex to manage focus movement among items.
Keyboard Interactions
- TabMoves focus to either the pressed item or the first item in the group.
- SpaceActivates/deactivates the item.
- EnterActivates/deactivates the item.
- ArrowDownMoves focus to the next item in the group.
- ArrowRightMoves focus to the next item in the group.
- ArrowUpMoves focus to the previous item in the group.
- ArrowLeftMoves focus to the previous item in the group.
- HomeMoves focus to the first item.
- EndMoves focus to the last item.