Skip to main content
View Zag.js on Github
Join the Discord server


A switch allows users to turn an individual option on or off.



  • Syncs with disabled state of fieldset
  • Syncs with form reset events
  • Can be toggled programmatically


To use the switch machine in your project, run the following command in your command line:

npm install @zag-js/switch @zag-js/react # or yarn add @zag-js/switch @zag-js/react

This command will install the framework agnostic switch logic and the reactive utilities for your framework of choice.


To set up the switch correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.


First, import the switch package into your project

import * as zagSwitch from "@zag-js/switch"

The switch package exports two key functions:

  • machine — The state machine logic for the switch widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

Next, import the required hooks and functions for your framework and use the switch machine in your project 🔥

import * as zagSwitch from "@zag-js/switch" import { useMachine, normalizeProps } from "@zag-js/react" function Checkbox() { const [state, send] = useMachine(zagSwitch.machine({ id: "1" })) const api = zagSwitch.connect(state, send, normalizeProps) return ( <label {...api.rootProps}> <input {...api.hiddenInputProps} /> <span {...api.controlProps}> <span {...api.thumbProps} /> </span> <span {...api.labelProps}>{api.isChecked ? "On" : "Off"}</span> </label> ) }

Disabling the switch

To make a switch disabled, set the context's disabled property to true

const [state, send] = useMachine( zagSwitch.machine({ disabled: true, }), )

Making the switch readonly

To make a switch readonly, set the context's readOnly property to true

const [state, send] = useMachine( zagSwitch.machine({ readOnly: true, }), )

Making it checked by default

To make a switch checked by default, set the context's checked property to true

const [state, send] = useMachine( zagSwitch.machine({ checked: true, }), )

Listening for changes

When the switch value changes, the onCheckChange callback is invoked.

const [state, send] = useMachine( zagSwitch.machine({ onCheckChange(details) { // details => { checked: boolean } console.log("switch is:", details.checked ? "On" : "Off") }, }), )

Usage within forms

To use switch within forms, use the exposed inputProps from the connect function and ensure you pass name value to the machine's context. It will render a hidden input and ensure the value changes get propagated to the form correctly.

const [state, send] = useMachine( zagSwitch.machine({ name: "feature", }), )

Styling guide

Earlier, we mentioned that each switch part has a data-part attribute added to them to select and style them in the DOM.

Focused State

When the switch input is focused, the data-focus attribute is added to the root, control and label parts.

[data-part="root"][data-focus] { /* styles for root focus state */ } [data-part="control"][data-focus] { /* styles for control focus state */ } [data-part="label"][data-focus] { /* styles for label focus state */ }

Disabled State

When the switch is disabled, the data-disabled attribute is added to the root, control and label parts.

[data-part="root"][data-disabled] { /* styles for root disabled state */ } [data-part="control"][data-disabled] { /* styles for control disabled state */ } [data-part="label"][data-disabled] { /* styles for label disabled state */ }

Invalid State

When the switch is invalid, the data-invalid attribute is added to the root, control and label parts.

[data-part="root"][data-invalid] { /* styles for root invalid state */ } [data-part="control"][data-invalid] { /* styles for control invalid state */ } [data-part="label"][data-invalid] { /* styles for label invalid state */ }

Methods and Properties

Machine Context

The switch machine exposes the following context properties:

  • idsPartial<{ root: string; input: string; control: string; label: string; thumb: string; }>The ids of the elements in the switch. Useful for composition.
  • labelstringSpecifies the localized strings that identifies the accessibility elements and their states
  • disabledbooleanWhether the switch is disabled.
  • invalidbooleanIf `true`, the switch is marked as invalid.
  • requiredbooleanIf `true`, the switch input is marked as required,
  • onCheckedChange(details: CheckedChangeDetails) => voidFunction to call when the switch is clicked.
  • checkedbooleanWhether the switch is checked.
  • namestringThe name of the input field in a switch (Useful for form submission).
  • formstringThe id of the form that the switch belongs to
  • valuestring | numberThe value of switch input. Useful for form submission.
  • 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 switch api exposes the following methods:

  • isCheckedbooleanWhether the checkbox is checked
  • isDisabledbooleanWhether the checkbox is disabled
  • isFocusedbooleanWhether the checkbox is focused
  • setChecked(checked: boolean) => voidFunction to set the checked state of the switch.
  • toggleChecked() => voidFunction to toggle the checked state of the checkbox

Edit this page on GitHub

On this page