XDSSwitch@xds/core · Switch
Usage
A toggle control for on/off states that take effect immediately. Supports labels, descriptions, loading states, and validation. Use it for settings or preferences that apply instantly. For changes requiring a form submission, use a checkbox instead.Best practices
| Guidance | Practices |
|---|---|
| Do | Use for settings that apply immediately — the toggle should take effect without a separate save action. |
| Do | Pair with a clear, concise label that describes the setting being controlled. |
| Don't | Use for options that require a form submission to take effect — use a checkbox instead. |
| Don't | Use a switch for multi-state values — it's strictly on/off. |
Import
tsimport {XDSSwitch} from '@xds/core/Switch'
Props
| Prop | Type | Description |
|---|---|---|
labelrequired | string | Label text for the switch (always rendered for accessibility). |
valuerequired | boolean | Whether the switch is on or off. |
ref | React.Ref<HTMLInputElement> | Ref forwarded to the underlying <input> element. |
onChange | (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void | Callback fired when the switch state changes. |
changeAction | (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void | Promise<void> | Async action fired after onChange. Triggers optimistic UI and shows a loading spinner until the promise resolves. |
isLoading | boolean (default: false) | Whether the switch is in a loading state, showing a spinner inside the thumb. |
isLabelHidden | boolean (default: false) | Visually hides the label while keeping it accessible to screen readers. |
description | string | Description text displayed below the label. |
isDisabled | boolean (default: false) | Whether the switch is disabled. |
isOptional | boolean (default: false) | Whether the field is optional. Mutually exclusive with isRequired. |
isRequired | boolean (default: false) | Whether the switch is required. Mutually exclusive with isOptional. |
status | XDSInputStatus | Status indicator with type and message. Displays a colored message box below the switch and sets aria-invalid when type is "error". |
onFocus | (e: FocusEvent<HTMLInputElement>) => void | Callback fired when the switch receives focus. |
onBlur | (e: FocusEvent<HTMLInputElement>) => void | Callback fired when the switch loses focus. |
labelIcon | XDSIconType | Icon displayed before the label text. See `npx xds docs icons` for valid semantic names. |
labelTooltip | string | Tooltip text shown in an info icon at the end of the label. |
labelPosition | 'start' | 'end' (default: 'end') | Which side of the switch the label appears on. "start" places the label before the switch. |
labelSpacing | 'default' | 'spread' (default: 'default') | Spacing behavior between label and switch. "spread" pushes them to opposite ends of the container (full width). |
Examples
Common configurations, variations, and states.Switch — DisabledDisabled switch with label and description for gated features.
tsx'use client';import {useState} from 'react';import {XDSSwitch} from '@xds/core/Switch';import {XDSCenter} from '@xds/core/Center';export default function SwitchDisabled() {const [value, setValue] = useState(false);return (<XDSCenter><XDSSwitchlabel="Premium feature"description="Upgrade to enable this option"value={value}onChange={setValue}isDisabled/></XDSCenter>);}
Switch — Settings PanelSettings panel with spread-spaced switches in a card.
tsx'use client';import {useState} from 'react';import {XDSSwitch} from '@xds/core/Switch';import {XDSCard} from '@xds/core/Card';import {XDSVStack} from '@xds/core/Layout';import {XDSCenter} from '@xds/core/Center';export default function SwitchSettingsPanel() {const [notifications, setNotifications] = useState(false);const [darkMode, setDarkMode] = useState(true);const [autoSave, setAutoSave] = useState(false);return (<XDSCenter width={350}><XDSCard><XDSVStack gap={4}><XDSSwitchlabel="Enable notifications"value={notifications}onChange={setNotifications}labelPosition="start"labelSpacing="spread"/><XDSSwitchlabel="Dark mode"value={darkMode}onChange={setDarkMode}labelPosition="start"labelSpacing="spread"/><XDSSwitchlabel="Auto-save"value={autoSave}onChange={setAutoSave}labelPosition="start"labelSpacing="spread"/></XDSVStack></XDSCard></XDSCenter>);}
Switch — With DescriptionToggle with a label and supporting description text.
tsx'use client';import {useState} from 'react';import {XDSSwitch} from '@xds/core/Switch';import {XDSCenter} from '@xds/core/Center';export default function SwitchWithDescription() {const [value, setValue] = useState(false);return (<XDSCenter><XDSSwitchlabel="Dark mode"description="Switch to a darker color scheme for reduced eye strain."value={value}onChange={setValue}/></XDSCenter>);}
Switch — With StatusSwitches with error, warning, and success validation states.
tsx'use client';import {useState} from 'react';import {XDSSwitch} from '@xds/core/Switch';import {XDSVStack} from '@xds/core/Layout';import {XDSCenter} from '@xds/core/Center';export default function SwitchWithStatus() {const [terms, setTerms] = useState(false);const [sharing, setSharing] = useState(true);const [twoFactor, setTwoFactor] = useState(true);return (<XDSCenter width={400}><XDSVStack gap={6}><XDSSwitchlabel="Accept terms and conditions"value={terms}onChange={setTerms}isRequiredstatus={{type: 'error',message: 'You must accept the terms to continue',}}/><XDSSwitchlabel="Share usage data"description="Help us improve by sharing anonymous usage statistics"value={sharing}onChange={setSharing}status={{type: 'warning',message: 'This data may be shared with partners',}}/><XDSSwitchlabel="Two-factor authentication"value={twoFactor}onChange={setTwoFactor}status={{type: 'success', message: 'Your account is now more secure'}}/></XDSVStack></XDSCenter>);}
Showcase source
tsx'use client';import {XDSSwitch} from '@xds/core/Switch';export default function SwitchShowcase() {return (<XDSSwitchlabel="Enable notifications"value={false}onChange={() => {}}/>);}