Toggle
A toggle is a two-state button that can be on or off. Use it for a single independent option (for multiple related options, see Toggle Group).
Features
- Controlled and uncontrolled pressed state
- Optional indicator part for icons or labels
aria-pressedfor assistive technology
Installation
Install the toggle package:
npm install @zag-js/toggle @zag-js/react # or yarn add @zag-js/toggle @zag-js/react
npm install @zag-js/toggle @zag-js/solid # or yarn add @zag-js/toggle @zag-js/solid
npm install @zag-js/toggle @zag-js/vue # or yarn add @zag-js/toggle @zag-js/vue
npm install @zag-js/toggle @zag-js/svelte # or yarn add @zag-js/toggle @zag-js/svelte
Anatomy
To set up the toggle 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 package:
import * as toggle from "@zag-js/toggle"
The toggle 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 * as toggle from "@zag-js/toggle" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" function Toggle() { const service = useMachine(toggle.machine, { id: useId() }) const api = toggle.connect(service, normalizeProps) return ( <button {...api.getRootProps()}> <span {...api.getIndicatorProps()} /> Bold </button> ) }
import * as toggle from "@zag-js/toggle" import { normalizeProps, useMachine } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" function Toggle() { const service = useMachine(toggle.machine, { id: createUniqueId() }) const api = createMemo(() => toggle.connect(service, normalizeProps)) return ( <button {...api().getRootProps()}> <span {...api().getIndicatorProps()} /> Bold </button> ) }
<script setup> import * as toggle from "@zag-js/toggle" 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> <button v-bind="api.getRootProps()"> <span v-bind="api.getIndicatorProps()" /> Bold </button> </template>
<script lang="ts"> import * as toggle from "@zag-js/toggle" import { normalizeProps, useMachine } from "@zag-js/svelte" const id = $props.id() const service = useMachine(toggle.machine, { id }) const api = $derived(toggle.connect(service, normalizeProps)) </script> <button {...api.getRootProps()}> <span {...api.getIndicatorProps()}></span> Bold </button>
Default pressed state
Use defaultPressed to start in the pressed (on) state when uncontrolled.
const service = useMachine(toggle.machine, { defaultPressed: true, })
Controlled pressed state
Use pressed and onPressedChange for controlled usage.
const service = useMachine(toggle.machine, { pressed, onPressedChange(nextPressed) { setPressed(nextPressed) }, })
Listening for changes
When the pressed state changes, onPressedChange is called with the next boolean value.
const service = useMachine(toggle.machine, { onPressedChange(pressed) { console.log(pressed ? "on" : "off") }, })
Disabling the toggle
Set disabled to true to prevent interaction.
const service = useMachine(toggle.machine, { disabled: true, })
Programmatic control
Use the API to set pressed state imperatively.
api.setPressed(true)
Indicator part
Render an optional element with getIndicatorProps() for icons or secondary visuals. The root remains the interactive
button.
<button {...api.getRootProps()}> <span {...api.getIndicatorProps()}> <BoldIcon /> </span> </button>
Styling guide
Each part includes a data-part attribute you can target in CSS.
Pressed state
When pressed, data-state is on or off on the root and indicator.
[data-part="root"][data-state="on"] { /* pressed */ } [data-part="indicator"][data-state="on"] { /* pressed indicator */ }
Disabled state
When disabled, data-disabled is set on the root and indicator.
[data-part="root"][data-disabled] { /* disabled */ }
Methods and Properties
Machine Context
The toggle machine exposes the following context properties:
disabledboolean | undefinedWhether the toggle is disabled.defaultPressedboolean | undefinedThe default pressed state of the toggle.pressedboolean | undefinedThe pressed state of the toggle.onPressedChange((pressed: boolean) => void) | undefinedEvent handler called when the pressed state of the toggle changes.
Machine API
The toggle api exposes the following methods:
pressedbooleanWhether the toggle is pressed.disabledbooleanWhether the toggle is disabled.setPressed(pressed: boolean) => voidSets the pressed state of the toggle.getRootProps() => T["element"]Props for the root `button` element.getIndicatorProps() => T["element"]Props for the optional visual indicator (e.g. icon) element.
Data Attributes
Accessibility
Implements a button with aria-pressed reflecting the pressed
state.
Keyboard Interactions
- SpaceEnterToggle the pressed state