Skip to main content

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).

Loading...

Features

  • Controlled and uncontrolled pressed state
  • Optional indicator part for icons or labels
  • aria-pressed for assistive technology

Installation

Install the toggle package:

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

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-part attribute to help identify them in the DOM.

rootindicator

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> ) }

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

Root
data-scope
toggle
data-part
root
data-state
"on" | "off"
data-pressed
Present when pressed
data-disabled
Present when disabled
Indicator
data-scope
toggle
data-part
indicator
data-disabled
Present when disabled
data-pressed
Present when pressed
data-state
"on" | "off"

Accessibility

Implements a button with aria-pressed reflecting the pressed state.

Keyboard Interactions

  • SpaceEnter
    Toggle the pressed state
Edit this page on GitHub