Checkbox
A checkbox allows users to make a binary choice, i.e. a choice between one of two possible mutually exclusive options.
Features
- Tri-state checkbox. i.e.
indeterminate
state - Syncs with
disabled
state of fieldset - Syncs with form
reset
events - Can be toggled programmatically
Installation
To use the checkbox machine in your project, run the following command in your command line:
npm install @zag-js/checkbox @zag-js/react # or yarn add @zag-js/checkbox @zag-js/react
npm install @zag-js/checkbox @zag-js/vue # or yarn add @zag-js/checkbox @zag-js/vue
npm install @zag-js/checkbox @zag-js/vue # or yarn add @zag-js/checkbox @zag-js/vue
npm install @zag-js/checkbox @zag-js/solid # or yarn add @zag-js/checkbox @zag-js/solid
This command will install the framework agnostic checkbox logic and the reactive utilities for your framework of choice.
Anatomy
To set up the checkbox 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.
Usage
First, import the checkbox package into your project
import * as checkbox from "@zag-js/checkbox"
The checkbox package exports two key functions:
machine
— The state machine logic for the checkbox 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 checkbox machine in your project 🔥
import * as checkbox from "@zag-js/checkbox" import { useMachine, normalizeProps } from "@zag-js/react" function Checkbox() { const [state, send] = useMachine(checkbox.machine({ id: "1" })) const api = checkbox.connect(state, send, normalizeProps) return ( <label {...api.getRootProps()}> <span {...api.getLabelProps()}> Input is {api.checked ? "checked" : "unchecked"} </span> <div {...api.getControlProps()} /> <input {...api.getHiddenInputProps()} /> </label> ) }
import * as checkbox from "@zag-js/checkbox" import { normalizeProps, useMachine } from "@zag-js/vue" import { defineComponent, h, Fragment, computed } from "vue" export default defineComponent({ name: "Checkbox", setup() { const [state, send] = useMachine(checkbox.machine({ id: "checkbox" })) const apiRef = computed(() => checkbox.connect(state.value, send, normalizeProps), ) return () => { const api = apiRef.value return ( <label {...api.getRootProps()}> <span {...api.getLabelProps()}> Input is {api.checked ? "checked" : "unchecked"} </span> <div {...api.getControlProps()} /> <input {...api.getHiddenInputProps()} /> </label> ) } }, })
<script setup> import * as checkbox from "@zag-js/checkbox" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const [state, send] = useMachine(checkbox.machine({ id: "1" })) const api = computed(() => checkbox.connect(state.value, send, normalizeProps), ) </script> <template> <label v-bind="api.getRootProps()"> <span v-bind="api.getLabelProps()"> Input is <span v-if="api.checked"> checked</span> <span v-else> unchecked</span> </span> <div v-bind="api.getControlProps()" /> <input v-bind="api.getHiddenInputProps()" /> </label> </template>
import * as checkbox from "@zag-js/checkbox" import { normalizeProps, useMachine } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" function Checkbox() { const [state, send] = useMachine(checkbox.machine({ id: createUniqueId() })) const api = createMemo(() => checkbox.connect(state, send, normalizeProps)) return ( <label {...api().getRootProps()}> <span {...api().getLabelProps()}> Input is {api().checked ? "checked" : "unchecked"} </span> <div {...api().getControlProps()} /> <input {...api().getHiddenInputProps()} /> </label> ) }
Indeterminate checkboxes
To make a checkbox indeterminate, set the context's indeterminate
property to
true
const [state, send] = useMachine( checkbox.machine({ indeterminate: true, }), )
Disabling the checkbox
To make a checkbox disabled, set the context's disabled
property to true
const [state, send] = useMachine( checkbox.machine({ disabled: true, }), )
Making it checked by default
To make a checkbox checked by default, set the context's checked
property to
true
const [state, send] = useMachine( checkbox.machine({ checked: true, }), )
Listening for changes
When the checkbox value changes, the onCheckChange
callback is invoked.
const [state, send] = useMachine( checkbox.machine({ onCheckChange(details) { // details => { checked: boolean } console.log("checkbox is:", details.checked) }, }), )
Usage within forms
To use checkbox within forms, use the exposed hiddenInputProps
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( checkbox.machine({ name: "fruits", }), )
Styling guide
Earlier, we mentioned that each checkbox part has a data-part
attribute added
to them to select and style them in the DOM.
Checked state
When the checkbox input is checked, the data-checked
attribute is added to the
root, control and label parts.
[data-part="root"][data-state="checked|unchecked|indeterminate"] { /* styles for when checkbox is checked */ } [data-part="control"][data-state="checked|unchecked|indeterminate"] { /* styles for when checkbox is checked */ } [data-part="label"][data-state="checked|unchecked|indeterminate"] { /* styles for when checkbox is checked */ }
Focused State
When the checkbox 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 checkbox 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 checkbox 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 checkbox machine exposes the following context properties:
ids
Partial<{ root: string; hiddenInput: string; control: string; label: string; }>
The ids of the elements in the checkbox. Useful for composition.disabled
boolean
Whether the checkbox is disabledinvalid
boolean
Whether the checkbox is invalidrequired
boolean
Whether the checkbox is requiredchecked
CheckedState
The checked state of the checkboxreadOnly
boolean
Whether the checkbox is read-onlyonCheckedChange
(details: CheckedChangeDetails) => void
The callback invoked when the checked state changes.name
string
The name of the input field in a checkbox. Useful for form submission.form
string
The id of the form that the checkbox belongs to.value
string
The value of checkbox input. Useful for form submission.dir
"ltr" | "rtl"
The document's text/writing direction.id
string
The unique identifier of the machine.getRootNode
() => ShadowRoot | Node | Document
A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The checkbox api
exposes the following methods:
checked
boolean
Whether the checkbox is checkeddisabled
boolean
Whether the checkbox is disabledindeterminate
boolean
Whether the checkbox is indeterminatefocused
boolean
Whether the checkbox is focusedcheckedState
CheckedState
The checked state of the checkboxsetChecked
(checked: CheckedState) => void
Function to set the checked state of the checkboxtoggleChecked
() => void
Function to toggle the checked state of the checkbox
Data Attributes
Accessibility
Keyboard Interactions
- SpaceToggle the checkbox
Edit this page on GitHub