Vision UI

Switch

Toggle built on Base UI with spring thumb motion, optional side content, and render-prop composition.

Import

import { Switch, switchVariants } from '@/components/switch'

Anatomy

The module exposes one namespace object. Switch is callable as the root control (same element as Switch.Root).

<Switch isSelected={isSelected} onSelectedChange={setIsSelected}>
  <Switch.Thumb />
  <Switch.StartContent>...</Switch.StartContent>
  <Switch.EndContent>...</Switch.EndContent>
</Switch>
  • Switch / Switch.Root: Track and interaction surface. Renders a default thumb when no Switch.Thumb is provided. Animates press scale and track background color from selection state. Uses isSelected / onSelectedChange (mapped to Base UI checked / onCheckedChange).
  • Switch.Thumb: Sliding thumb with spring motion. Supports custom content and render functions.
  • Switch.StartContent: Optional left slot (typically visible when off).
  • Switch.EndContent: Optional right slot (typically visible when on).

Usage

Basic

<Switch isSelected={isSelected} onSelectedChange={setIsSelected} />

Custom thumb

<Switch isSelected={isSelected} onSelectedChange={setIsSelected}>
  <Switch.Thumb className="bg-white" />
</Switch>

Start and end content

<Switch isSelected={isSelected} onSelectedChange={setIsSelected}>
  <Switch.Thumb />
  <Switch.StartContent>
    <XIcon />
  </Switch.StartContent>
  <Switch.EndContent>
    <CheckIcon />
  </Switch.EndContent>
</Switch>

Toggle sounds

By default the root plays toggleOn when turned on and toggleOff when turned off. Pass isSoundDisabled to silence them (for example when another control already owns interaction audio).

<Switch isSoundDisabled isSelected={isSelected} onSelectedChange={setIsSelected} />

Render functions

<Switch isSelected={isSelected} onSelectedChange={setIsSelected}>
  {({ isSelected, isDisabled }) => (
    <>
      <Switch.Thumb>
        {({ isSelected }) => (isSelected ? <CheckIcon /> : <XIcon />)}
      </Switch.Thumb>
    </>
  )}
</Switch>

Example

import { useState } from 'react'
import { Switch } from '@/components/switch'

export default function SwitchExample() {
  const [isSelected, setIsSelected] = useState(false)

  return (
    <Switch
      isSelected={isSelected}
      onSelectedChange={setIsSelected}
      aria-label="Notifications"
    />
  )
}

API Reference

Switch (Switch.Root)

Prop

Type

size mirrors switchVariants in switch.styles.ts.

Switch.Thumb

Prop

Type

Switch.StartContent / Switch.EndContent

Plain span slots with absolute positioning inside the track. Accept standard React.HTMLAttributes<HTMLSpanElement>.

SwitchProps

Type alias for SwitchRootProps.

On this page