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>