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

GuidancePractices
DoUse for settings that apply immediately — the toggle should take effect without a separate save action.
DoPair with a clear, concise label that describes the setting being controlled.
Don'tUse for options that require a form submission to take effect — use a checkbox instead.
Don'tUse a switch for multi-state values — it's strictly on/off.

Import

ts
import {XDSSwitch} from '@xds/core/Switch'

Props

PropTypeDescription
labelrequired
stringLabel text for the switch (always rendered for accessibility).
valuerequired
booleanWhether the switch is on or off.
ref
React.Ref<HTMLInputElement>Ref forwarded to the underlying <input> element.
onChange
(checked: boolean, e: ChangeEvent<HTMLInputElement>) => voidCallback 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
stringDescription 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
XDSInputStatusStatus 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>) => voidCallback fired when the switch receives focus.
onBlur
(e: FocusEvent<HTMLInputElement>) => voidCallback fired when the switch loses focus.
labelIcon
XDSIconTypeIcon displayed before the label text. See `npx xds docs icons` for valid semantic names.
labelTooltip
stringTooltip 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>
<XDSSwitch
label="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}>
<XDSSwitch
label="Enable notifications"
value={notifications}
onChange={setNotifications}
labelPosition="start"
labelSpacing="spread"
/>
<XDSSwitch
label="Dark mode"
value={darkMode}
onChange={setDarkMode}
labelPosition="start"
labelSpacing="spread"
/>
<XDSSwitch
label="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>
<XDSSwitch
label="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}>
<XDSSwitch
label="Accept terms and conditions"
value={terms}
onChange={setTerms}
isRequired
status={{
type: 'error',
message: 'You must accept the terms to continue',
}}
/>
<XDSSwitch
label="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',
}}
/>
<XDSSwitch
label="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 (
<XDSSwitch
label="Enable notifications"
value={false}
onChange={() => {}}
/>
);
}