Skip to main content

Switch

  • Component overview: Toggle control that switches between On and Off states at a fixed size.
  • Size baseline: Track 36×20px, thumb 16×16px, 2px padding on each side.
  • Implementation note: The track retains the structural skeleton; visuals are controlled by design tokens. loading currently preserves the Default visual and disables interaction.
  • Figma spec

States

6 states: On / Off × Enabled / Disabled / Loading.

Result
Loading...
Live Editor
<div style={{ display: 'flex', gap: 32, flexWrap: 'wrap', alignItems: 'center' }}>
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
    <Switch defaultChecked aria-label="demo on" />
    <span style={{ fontSize: 12, color: '#999' }}>On</span>
  </div>
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
    <Switch aria-label="demo off" />
    <span style={{ fontSize: 12, color: '#999' }}>Off</span>
  </div>
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
    <Switch defaultChecked disabled aria-label="demo disabled on" />
    <span style={{ fontSize: 12, color: '#999' }}>Disabled On</span>
  </div>
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
    <Switch disabled aria-label="demo disabled off" />
    <span style={{ fontSize: 12, color: '#999' }}>Disabled Off</span>
  </div>
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
    <Switch defaultChecked loading aria-label="demo loading on" />
    <span style={{ fontSize: 12, color: '#999' }}>Loading On</span>
  </div>
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
    <Switch loading aria-label="demo loading off" />
    <span style={{ fontSize: 12, color: '#999' }}>Loading Off</span>
  </div>
</div>
StateTrack colorThumb colorOpacity
On + EnabledForegrounds/Toggle On#1573D1Foregrounds/White#FFFFFF100%
Off + EnabledForegrounds/Toggle Off#D6D6D6Foregrounds/White#FFFFFF100%
On + DisabledForegrounds/Toggle On#1573D1Foregrounds/White#FFFFFF60%
Off + DisabledForegrounds/Toggle Off#D6D6D6Foregrounds/White#FFFFFF60%
On + LoadingForegrounds/Toggle On#1573D1Foregrounds/White#FFFFFF100%
Off + LoadingForegrounds/Toggle Off#D6D6D6Foregrounds/White#FFFFFF100%

Controlled Mode

Result
Loading...
Live Editor
function ControlledSwitch() {
  const [checked, setChecked] = useState(false)
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
      <Switch checked={checked} onCheckedChange={setChecked} aria-label="controlled" />
        <span style={{ fontSize: 14 }}>{checked ? 'On' : 'Off'}</span>
    </div>
  )
}

Size Spec

DimensionValue
Track width36px
Track height20px
Track border radius5px
Thumb size16×16px
Thumb border radiusRadius_5 - 2px
Thumb padding2px

Props

PropTypeDefaultDescription
checkedboolean-Controlled checked state
defaultCheckedbooleanfalseInitial checked state (uncontrolled)
onCheckedChange(checked: boolean) => void-State change callback
disabledbooleanfalseDisabled state (60% opacity)
loadingbooleanfalseLoading state — currently preserves Default visual and disables interaction
aria-labelstring-Accessibility label