Switch
A switch allows users to turn an individual option on or off.
Features
- Sync with
disabledstate of fieldset - Sync with form
resetevents - Can be toggled programmatically
Installation
Install the switch package:
npm install @zag-js/switch @zag-js/react # or yarn add @zag-js/switch @zag-js/react
npm install @zag-js/switch @zag-js/solid # or yarn add @zag-js/switch @zag-js/solid
npm install @zag-js/switch @zag-js/vue # or yarn add @zag-js/switch @zag-js/vue
npm install @zag-js/switch @zag-js/svelte # or yarn add @zag-js/switch @zag-js/svelte
Anatomy
Check the switch anatomy and part names.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
Import the switch package:
import * as zagSwitch from "@zag-js/switch"
The switch 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 zagSwitch from "@zag-js/switch" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" function Switch() { const service = useMachine(zagSwitch.machine, { id: useId() }) const api = zagSwitch.connect(service, normalizeProps) return ( <label {...api.getRootProps()}> <input {...api.getHiddenInputProps()} /> <span {...api.getControlProps()}> <span {...api.getThumbProps()} /> </span> <span {...api.getLabelProps()}>{api.checked ? "On" : "Off"}</span> </label> ) }
import * as zagSwitch from "@zag-js/switch" import { normalizeProps, useMachine } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" function Checkbox() { const service = useMachine(zagSwitch.machine, { id: createUniqueId() }) const api = createMemo(() => zagSwitch.connect(service, normalizeProps)) return ( <label {...api().getRootProps()}> <input {...api().getHiddenInputProps()} /> <span {...api().getControlProps()}> <span {...api().getThumbProps()} /> </span> <span {...api().getLabelProps()}>{api().checked ? "On" : "Off"}</span> </label> ) }
<script setup> import * as zagSwitch from "@zag-js/switch" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const service = useMachine(zagSwitch.machine, { id: "1" }) const api = computed(() => zagSwitch.connect(service, normalizeProps)) </script> <template> <label v-bind="api.getRootProps()"> <input v-bind="api.getHiddenInputProps()" /> <span v-bind="api.getControlProps()"> <span v-bind="api.getThumbProps()" /> </span> <span v-bind="api.getLabelProps()"> <span v-if="api.checked">On</span> <span v-else>Off</span> </span> </label> </template>
<script lang="ts"> import { normalizeProps, useMachine } from "@zag-js/svelte" import * as zagSwitch from "@zag-js/switch" const id = $props.id() const service = useMachine(zagSwitch.machine, { id, name: "switch", }) const api = $derived(zagSwitch.connect(service, normalizeProps)) </script> <label {...api.getRootProps()}> <input {...api.getHiddenInputProps()} /> <span {...api.getControlProps()}> <span {...api.getThumbProps()}></span> </span> <span {...api.getLabelProps()}>{api.checked ? "On" : "Off"}</span> </label>
Making it checked by default
Use the defaultChecked property to make a switch checked by default.
const service = useMachine(zagSwitch.machine, { defaultChecked: true, })
Controlled checked state
Use checked and onCheckedChange for controlled usage.
const service = useMachine(zagSwitch.machine, { checked, onCheckedChange(details) { setChecked(details.checked) }, })
Listening for changes
When the switch value changes, the onCheckedChange callback is invoked.
const service = useMachine(zagSwitch.machine, { onCheckedChange(details) { // details => { checked: boolean } console.log("switch is:", details.checked ? "On" : "Off") }, })
Programmatic toggle
Use the connected API when you need imperative control.
api.setChecked(true) api.toggleChecked()
Usage within forms
To use switch in forms, set name and render api.getHiddenInputProps().
const service = useMachine(zagSwitch.machine, { name: "feature", })
Custom form value
Set value to customize the submitted form value when checked.
const service = useMachine(zagSwitch.machine, { name: "notifications", value: "enabled", })
Styling guide
Each switch part includes a data-part attribute you can target in CSS.
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; hiddenInput: string; control: string; label: string; thumb: string; }> | undefinedThe ids of the elements in the switch. Useful for composition.labelstring | undefinedSpecifies the localized strings that identifies the accessibility elements and their statesdisabledboolean | undefinedWhether the switch is disabled.invalidboolean | undefinedIf `true`, the switch is marked as invalid.requiredboolean | undefinedIf `true`, the switch input is marked as required,readOnlyboolean | undefinedWhether the switch is read-onlyonCheckedChange((details: CheckedChangeDetails) => void) | undefinedFunction to call when the switch is clicked.checkedboolean | undefinedThe controlled checked state of the switchdefaultCheckedboolean | undefinedThe initial checked state of the switch when rendered. Use when you don't need to control the checked state of the switch.namestring | undefinedThe name of the input field in a switch (Useful for form submission).formstring | undefinedThe id of the form that the switch belongs tovaluestring | number | undefinedThe value of switch input. Useful for form submission.dir"ltr" | "rtl" | undefinedThe document's text/writing direction.idstringThe unique identifier of the machine.getRootNode(() => ShadowRoot | Node | Document) | undefinedA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The switch api exposes the following methods:
checkedbooleanWhether the switch is checkeddisabledboolean | undefinedWhether the switch is disabledfocusedboolean | undefinedWhether the switch is focusedsetChecked(checked: boolean) => voidSets the checked state of the switch.toggleCheckedVoidFunctionToggles the checked state of the switch.
Data Attributes
Accessibility
Adheres to the Switch WAI-ARIA design pattern
Keyboard Interactions
- SpaceEnterToggle the switch