XDSCheckboxInput@xds/core · CheckboxInput
Usage
CheckboxInput toggles a single on/off value. Use it for settings like "Enable notifications", terms acceptance, or opt-in choices. For multiple checkboxes in a group, use CheckboxList instead.Best practices
| Guidance | Practices |
|---|---|
| Do | Always provide a visible label so the user knows what they are toggling. Use isLabelHidden only when surrounding context makes it obvious. |
| Do | Add a description for choices that need extra context, like explaining what "Share usage data" actually shares. |
| Do | Use the indeterminate state for "select all" checkboxes when only some items in a group are selected. |
| Don't | Use a checkbox for mutually exclusive choices — use RadioList when only one option can be selected. |
| Don't | Use a checkbox for actions that take effect immediately — use a toggle switch or button instead. |
Anatomy
| Element | Description | |
|---|---|---|
| Checkbox | required | The check box itself — unchecked, checked, or indeterminate. |
| Label | required | Text describing what the checkbox controls. Always present for accessibility. |
| Description | Helper text below the label with additional context. | |
| Status message | An error, warning, or success message below the checkbox. |
Import
tsimport {XDSCheckboxInput} from '@xds/core/CheckboxInput'
Props
| Prop | Type | Description |
|---|---|---|
labelrequired | string | Label text for the checkbox (always rendered for accessibility). |
valuerequired | boolean | 'indeterminate' | Whether the checkbox is checked, unchecked, or indeterminate. |
ref | React.Ref<HTMLInputElement> | Ref forwarded to the underlying <input> element. |
isLabelHidden | boolean (default: false) | Whether to visually hide the label (still accessible to screen readers). |
description | string | Description text displayed below the label. |
onChange | (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void | Callback fired when the checkbox state changes. |
changeAction | (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void | Promise<void> | Async action on change. Fires after onChange if not prevented. Shows loading spinner while pending. |
isLoading | boolean (default: false) | Whether the checkbox is in a loading state. Shows spinner and prevents interaction. |
isDisabled | boolean (default: false) | Whether the checkbox is disabled. |
isOptional | boolean (default: false) | Whether the field is optional. Mutually exclusive with isRequired. |
isRequired | boolean (default: false) | Whether the checkbox is required. Mutually exclusive with isOptional. |
size | 'sm' | 'md' (default: 'md') | The size of the checkbox. sm for compact layouts, md for default. |
onFocus | (e: FocusEvent<HTMLInputElement>) => void | Callback fired when the checkbox receives focus. |
onBlur | (e: FocusEvent<HTMLInputElement>) => void | Callback fired when the checkbox loses focus. |
labelIcon | XDSIconType | Icon to display before the label text. See `npx xds docs icons` for valid semantic names. |
status | { type: 'error' | 'warning' | 'success', message: string } | Status indicator. Displays a colored message box below the checkbox and sets aria-invalid for errors. |
Examples
Common configurations, variations, and states.CheckboxInput — IndeterminateA
tsx'use client';import {useState} from 'react';import {XDSCheckboxInput} from '@xds/core/CheckboxInput';import {XDSStack} from '@xds/core/Layout';import {XDSDivider} from '@xds/core/Divider';export default function CheckboxInputIndeterminateState() {const [items, setItems] = useState({email: true,push: false,sms: true,slack: false,});const checkedCount = Object.values(items).filter(Boolean).length;const totalCount = Object.keys(items).length;const selectAllValue =checkedCount === 0? false: checkedCount === totalCount? true: ('indeterminate' as const);const handleSelectAll = (checked: boolean) => {setItems({email: checked, push: checked, sms: checked, slack: checked});};return (<XDSStack direction="vertical" gap={3}><XDSCheckboxInputlabel="Select all notifications"description={`${checkedCount} of ${totalCount} enabled`}value={selectAllValue}onChange={handleSelectAll}/><XDSDivider /><XDSStack direction="vertical" gap={3}><XDSCheckboxInputlabel="Email notifications"value={items.email}onChange={v => setItems(prev => ({...prev, email: v}))}/><XDSCheckboxInputlabel="Push notifications"value={items.push}onChange={v => setItems(prev => ({...prev, push: v}))}/><XDSCheckboxInputlabel="SMS alerts"value={items.sms}onChange={v => setItems(prev => ({...prev, sms: v}))}/><XDSCheckboxInputlabel="Slack messages"value={items.slack}onChange={v => setItems(prev => ({...prev, slack: v}))}/></XDSStack></XDSStack>);}
CheckboxInput — StatesCheckboxes with labels and descriptions in checked, unchecked, and disabled states. Each checkbox controls a single on/off setting. Add a description to explain what the setting does.
tsx'use client';import {useState} from 'react';import {XDSCheckboxInput} from '@xds/core/CheckboxInput';import {XDSStack} from '@xds/core/Layout';export default function CheckboxInputBasic() {const [checked, setChecked] = useState<boolean | 'indeterminate'>(true);const [unchecked, setUnchecked] = useState<boolean | 'indeterminate'>(false);const [disabled, setDisabled] = useState<boolean | 'indeterminate'>(false);const [indeterminate, setIndeterminate] = useState<boolean | 'indeterminate'>('indeterminate',);return (<XDSStack direction="vertical" gap={4}><XDSCheckboxInputlabel="Checked"description="This checkbox is currently on."value={checked}onChange={setChecked}/><XDSCheckboxInputlabel="Unchecked"description="This checkbox is currently off."value={unchecked}onChange={setUnchecked}/><XDSCheckboxInputlabel="Disabled"description="This checkbox cannot be changed."value={disabled}onChange={setDisabled}isDisabled/><XDSCheckboxInputlabel="Indeterminate"description="This checkbox represents a partial selection."value={indeterminate}onChange={setIndeterminate}/></XDSStack>);}
CheckboxInput — StatusCheckboxes with error, warning, and success validation messages. Use the status prop to show feedback after form validation — errors block submission, warnings inform, and success confirms.
tsx'use client';import {useState} from 'react';import {XDSCheckboxInput} from '@xds/core/CheckboxInput';import {XDSStack} from '@xds/core/Layout';export default function CheckboxInputStatusVariations() {const [error, setError] = useState<boolean | 'indeterminate'>(false);const [warning, setWarning] = useState<boolean | 'indeterminate'>(true);const [success, setSuccess] = useState<boolean | 'indeterminate'>(true);return (<XDSStack direction="vertical" gap={4}><XDSCheckboxInputlabel="Error"description="Required field that has not been accepted."value={error}onChange={setError}status={{type: 'error',message: 'You must accept the terms to continue',}}/><XDSCheckboxInputlabel="Warning"description="Enabled setting with a side effect to be aware of."value={warning}onChange={setWarning}status={{type: 'warning',message: 'This data may be shared with partners',}}/><XDSCheckboxInputlabel="Success"description="Confirmed setting that has been verified."value={success}onChange={setSuccess}status={{type: 'success', message: 'Your email has been verified'}}/></XDSStack>);}
Showcase source
tsx'use client';import {useState} from 'react';import {XDSCheckboxInput} from '@xds/core/CheckboxInput';import {XDSStack} from '@xds/core/Layout';export default function CheckboxInputShowcase() {const [notifications, setNotifications] = useState(true);const [marketing, setMarketing] = useState(false);return (<XDSStack direction="vertical" gap={2}><XDSCheckboxInputlabel="Checked"value={notifications}onChange={setNotifications}/><XDSCheckboxInputlabel="Unchecked"value={marketing}onChange={setMarketing}/></XDSStack>);}