Switch

A sliding toggle control. Supports controlled and uncontrolled usage, six semantic color palettes, two sizes, four visual variants, and custom thumb icons.

Architecture: the root element is a <label> wrapping a visually-hidden <input type="checkbox" role="switch">, a pill-shaped track, and optional label text. Clicking anywhere on the root toggles the switch. All state transitions are driven by CSS - no JavaScript animation.

Examples

Default

<Switch color="default" size="md" variant="outside" aria-label="Toggle" />

Colors

default
primary
secondary
success
error
info
warning
<Flex flexDirection="column" gap={2}>
  {switchColorTokens.map((color) => (
    <Flex key={color} flexDirection="row" alignItems="center" gap={3}>
      <Typography variant="caption" color="secondary" width="6rem" flexShrink={0} m={0}>
        {color}
      </Typography>
      <Switch color={color} aria-label={`${color} off`} />
      <Switch color={color} checked onChange={() => {}} aria-label={`${color} on`} />
    </Flex>
  ))}
</Flex>

Sizes

outside
sm
md
lg
inside
sm
md
lg
<Flex flexDirection="column" gap={3}>
  {(['outside', 'inside'] as const).map((variant) => (
    <Flex key={variant} flexDirection="row" gap={4} alignItems="center">
      <Typography variant="caption" color="secondary" width="5rem" flexShrink={0} m={0}>
        {variant}
      </Typography>
      {(['sm', 'md', 'lg'] as const).map((size) => (
        <Flex key={size} flexDirection="column" alignItems="center" gap={1}>
          <Switch
            variant={variant}
            size={size}
            color="primary"
            checked
            onChange={() => {}}
            aria-label={`${variant} ${size}`}
          />
          <Typography variant="caption" color="secondary" m={0}>
            {size}
          </Typography>
        </Flex>
      ))}
    </Flex>
  ))}
</Flex>

Disabled

Disabled off
Disabled on
<Flex flexDirection="column" gap={2}>
  {(
    [
      { label: 'Disabled off', props: { disabled: true } },
      { label: 'Disabled on', props: { disabled: true, checked: true, onChange: () => {} } },
    ] as const
  ).map(({ label, props }) => (
    <Flex key={label} flexDirection="row" alignItems="center" gap={2}>
      <Typography variant="caption" color="secondary" width="8rem" flexShrink={0} m={0}>
        {label}
      </Typography>
      <Switch color="primary" {...props} aria-label={label} />
    </Flex>
  ))}
</Flex>

With Label

<Switch color="primary">Enable dark mode</Switch>

Variants

outside
inside
<Flex flexDirection="column" gap={3}>
  {(['outside', 'inside'] as const).map((variant) => (
    <Flex key={variant} flexDirection="row" alignItems="center" gap={3}>
      <Typography variant="caption" color="secondary" width="5rem" flexShrink={0} m={0}>
        {variant}
      </Typography>
      <Switch variant={variant} color="primary" aria-label={`${variant} off`} />
      <Switch
        variant={variant}
        color="primary"
        checked
        onChange={() => {}}
        aria-label={`${variant} on`}
      />
    </Flex>
  ))}
</Flex>

Marked

outside
inside
<Flex flexDirection="column" gap={3}>
  {(['outside', 'inside'] as const).map((variant) => (
    <Flex key={variant} flexDirection="row" alignItems="center" gap={3}>
      <Typography variant="caption" color="secondary" width="5rem" flexShrink={0} m={0}>
        {variant}
      </Typography>
      <Switch variant={variant} marked color="primary" aria-label={`${variant} marked off`} />
      <Switch
        variant={variant}
        marked
        color="primary"
        checked
        onChange={() => {}}
        aria-label={`${variant} marked on`}
      />
    </Flex>
  ))}
</Flex>

With Icons

sm
md
lg
const { checked, onChange, ...props }: Partial<SwitchProps> = {}

<Paper p={2}>
  <Flex flexDirection="column" gap={3}>
    {(['sm', 'md', 'lg'] as const).map((size) => (
      <Flex key={size} flexDirection="row" alignItems="center" gap={3}>
        <Typography variant="caption" color="secondary" width="3rem" flexShrink={0} m={0}>
          {size}
        </Typography>
        <Switch
          size={size}
          variant="outside"
          color="primary"
          {...props}
          checked={checked}
          onChange={onChange}
          icon={<MoonIcon />}
          checkedIcon={<SunIcon />}
          aria-label={`outside ${size} theme toggle`}
        />
        <Switch
          variant="inside"
          size={size}
          color="primary"
          {...props}
          checked={checked}
          onChange={onChange}
          icon={<MoonIcon />}
          checkedIcon={<SunIcon />}
          aria-label={`inside ${size} theme toggle`}
        />
      </Flex>
    ))}
  </Flex>
</Paper>

Switch API reference