Skip to main content

Overview

The Switch component provides an accessible toggle switch with smooth animations and optional descriptions. Built on React Aria Components for full keyboard navigation and screen reader support.

Import

import { Switch } from 'stride-ds';

Basic Usage

import { Switch } from 'stride-ds';

function Example() {
  return <Switch>Enable notifications</Switch>;
}

Sizes

Three size options are available:
<Switch size="sm">Small switch</Switch>
<Switch size="md">Medium switch</Switch>
<Switch size="lg">Large switch</Switch>

With Description

Add supporting text below the main label:
<Switch 
  description="Get notified when someone mentions you in a comment or assigns you a task."
>
  Enable notifications
</Switch>

States

On/Off

<Switch>Off (default)</Switch>
<Switch isSelected>On</Switch>

Disabled

<Switch isDisabled>Disabled</Switch>
<Switch isSelected isDisabled>Disabled & On</Switch>

Props

size
'sm' | 'md' | 'lg'
default:"'md'"
Size of the switch. Affects track and thumb dimensions.
children
React.ReactNode
The label text for the switch.
description
React.ReactNode
Additional description text displayed below the label.
isSelected
boolean
default:"false"
Whether the switch is on (controlled).
defaultSelected
boolean
default:"false"
Whether the switch is initially on (uncontrolled).
isDisabled
boolean
default:"false"
Whether the switch is disabled.
onChange
(isSelected: boolean) => void
Handler called when the switch state changes.
className
string
Additional CSS classes to apply.
value
string
The value of the switch in a form.
name
string
The name of the switch in a form.

Accessibility

The Switch component is built with React Aria Components and provides:
  • Keyboard Navigation: Space to toggle, Tab to move focus
  • Focus Management: Clear focus indicators
  • Screen Reader Support: Proper ARIA attributes including role="switch" and aria-checked
  • Label Association: Automatic association between switch and label
  • State Announcements: On/off state changes are announced to screen readers

Best Practices

  1. Always provide a label via children or use aria-label:
    <Switch>Enable feature</Switch>
    // or
    <Switch aria-label="Enable feature" />
    
  2. Use description for additional context:
    <Switch description="This will enable advanced features">
      Enable advanced mode
    </Switch>
    
  3. Use switches for immediate action toggles, not for form submission:
    // Good: Immediate effect
    <Switch onChange={toggleDarkMode}>Dark mode</Switch>
    
    // Bad: Should use checkbox in a form instead
    <Switch>Accept terms</Switch>
    

Examples

All States

<div className="flex flex-col space-y-4">
  <Switch>Off</Switch>
  <Switch isSelected>On</Switch>
  <Switch isDisabled>Disabled</Switch>
  <Switch isSelected isDisabled>Disabled & On</Switch>
</div>

All Sizes with States

<div className="flex flex-col space-y-6">
  <div>
    <h3 className="text-sm font-medium mb-3">Small</h3>
    <div className="space-y-3">
      <Switch size="sm">Dark mode</Switch>
      <Switch size="sm" isSelected>Auto-save</Switch>
      <Switch size="sm" isDisabled>Beta features</Switch>
    </div>
  </div>

  <div>
    <h3 className="text-sm font-medium mb-3">Medium</h3>
    <div className="space-y-3">
      <Switch size="md">Dark mode</Switch>
      <Switch size="md" isSelected>Auto-save</Switch>
      <Switch size="md" isDisabled>Beta features</Switch>
    </div>
  </div>

  <div>
    <h3 className="text-sm font-medium mb-3">Large</h3>
    <div className="space-y-3">
      <Switch size="lg">Dark mode</Switch>
      <Switch size="lg" isSelected>Auto-save</Switch>
      <Switch size="lg" isDisabled>Beta features</Switch>
    </div>
  </div>
</div>

Settings Panel

import { Switch } from 'stride-ds';
import { useState } from 'react';

function SettingsPanel() {
  const [settings, setSettings] = useState({
    notifications: true,
    darkMode: false,
    autoSave: true,
    analytics: false,
  });

  return (
    <div className="space-y-4">
      <h3 className="text-lg font-semibold">Preferences</h3>
      
      <Switch
        isSelected={settings.notifications}
        onChange={(checked) => 
          setSettings({ ...settings, notifications: checked })
        }
        description="Receive notifications about mentions and assignments"
      >
        Enable notifications
      </Switch>

      <Switch
        isSelected={settings.darkMode}
        onChange={(checked) => 
          setSettings({ ...settings, darkMode: checked })
        }
        description="Use dark theme throughout the application"
      >
        Dark mode
      </Switch>

      <Switch
        isSelected={settings.autoSave}
        onChange={(checked) => 
          setSettings({ ...settings, autoSave: checked })
        }
        description="Automatically save your work every 30 seconds"
      >
        Auto-save
      </Switch>

      <Switch
        isSelected={settings.analytics}
        onChange={(checked) => 
          setSettings({ ...settings, analytics: checked })
        }
        description="Help us improve by sharing anonymous usage data"
      >
        Analytics
      </Switch>
    </div>
  );
}

Without Label (Icon Only)

<Switch aria-label="Toggle dark mode" />

Controlled Component

import { useState } from 'react';
import { Switch } from 'stride-ds';

function ControlledExample() {
  const [isEnabled, setIsEnabled] = useState(false);

  return (
    <div>
      <Switch 
        isSelected={isEnabled}
        onChange={setIsEnabled}
      >
        Feature toggle
      </Switch>
      
      <p className="mt-4">
        Status: {isEnabled ? 'Enabled' : 'Disabled'}
      </p>
    </div>
  );
}

With Long Description

<Switch 
  description="This will enable the advanced notification system that includes push notifications, email alerts, and in-app notifications. You can customize these settings later in your preferences."
>
  Enable advanced notification system
</Switch>

Immediate Action Example

import { Switch } from 'stride-ds';
import { useState, useEffect } from 'react';

function DarkModeToggle() {
  const [isDark, setIsDark] = useState(false);

  useEffect(() => {
    // Apply dark mode class immediately when switch changes
    if (isDark) {
      document.documentElement.classList.add('dark');
    } else {
      document.documentElement.classList.remove('dark');
    }
  }, [isDark]);

  return (
    <Switch 
      isSelected={isDark}
      onChange={setIsDark}
      description="Toggle between light and dark theme"
    >
      Dark mode
    </Switch>
  );
}

React Hook Form Integration

The Switch component works with React Hook Form:
import { useForm, Controller } from 'react-hook-form';
import { Switch } from 'stride-ds';

function FormExample() {
  const { control, handleSubmit } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="notifications"
        control={control}
        render={({ field }) => (
          <Switch
            isSelected={field.value}
            onChange={field.onChange}
            description="Receive email notifications"
          >
            Enable notifications
          </Switch>
        )}
      />
    </form>
  );
}

Differences from Checkbox

Use Switch when:
  • The action takes effect immediately
  • You’re toggling a system state (on/off, enabled/disabled)
  • No form submission is required
Use Checkbox when:
  • The action is part of a form submission
  • Multiple selections are needed
  • The action represents agreement or selection

Build docs developers (and LLMs) love