Switch
Switches toggle the state of a single setting on or off.
Switches are the preferred way to adjust settings on mobile. The option that the switch controls, as well as the state it's in, should be made clear from the corresponding inline label.
import Switch from '@mui/material/Switch';
const label = { slotProps: { input: { 'aria-label': 'Switch demo' } } };
export default function BasicSwitches() {
return (
<div>
<Switch {...label} defaultChecked />
<Switch {...label} />
<Switch {...label} disabled defaultChecked />
<Switch {...label} disabled />
</div>
);
}
Label
You can provide a label to the Switch thanks to the FormControlLabel component.
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
export default function SwitchLabels() {
return (
<FormGroup>
<FormControlLabel control={<Switch defaultChecked />} label="Label" />
<FormControlLabel required control={<Switch />} label="Required" />
<FormControlLabel disabled control={<Switch />} label="Disabled" />
</FormGroup>
);
}
Size
Use the size prop to change the size of the switch.
import Switch from '@mui/material/Switch';
const label = { slotProps: { input: { 'aria-label': 'Size switch demo' } } };
export default function SwitchesSize() {
return (
<div>
<Switch {...label} defaultChecked size="small" />
<Switch {...label} defaultChecked />
</div>
);
}
import { alpha, styled } from '@mui/material/styles';
import { pink } from '@mui/material/colors';
import Switch from '@mui/material/Switch';
const PinkSwitch = styled(Switch)(({ theme }) => ({
'& .MuiSwitch-switchBase.Mui-checked': {
color: pink[600],
'&:hover': {
backgroundColor: alpha(pink[600], theme.palette.action.hoverOpacity),
},
},
'& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': {
backgroundColor: pink[600],
},
}));
const label = { slotProps: { input: { 'aria-label': 'Color switch demo' } } };
export default function ColorSwitches() {
return (
<div>
<Switch {...label} defaultChecked />
<Switch {...label} defaultChecked color="secondary" />
<Switch {...label} defaultChecked color="warning" />
<Switch {...label} defaultChecked color="default" />
<PinkSwitch {...label} defaultChecked />
</div>
);
}
Controlled
You can control the switch with the checked and onChange props:
import * as React from 'react';
import Switch from '@mui/material/Switch';
export default function ControlledSwitches() {
const [checked, setChecked] = React.useState(true);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setChecked(event.target.checked);
};
return (
<Switch
checked={checked}
onChange={handleChange}
slotProps={{ input: { 'aria-label': 'controlled' } }}
/>
);
}
Switches with FormGroup
FormGroup is a helpful wrapper used to group selection controls components that provides an easier API.
However, you are encouraged to use Checkboxes instead if multiple related controls are required. (See: When to use).
import * as React from 'react';
import FormLabel from '@mui/material/FormLabel';
import FormControl from '@mui/material/FormControl';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormHelperText from '@mui/material/FormHelperText';
import Switch from '@mui/material/Switch';
export default function SwitchesGroup() {
const [state, setState] = React.useState({
gilad: true,
jason: false,
antoine: true,
});
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setState({
...state,
[event.target.name]: event.target.checked,
});
};
return (
<FormControl component="fieldset" variant="standard">
<FormLabel component="legend">Assign responsibility</FormLabel>
<FormGroup>
<FormControlLabel
control={
<Switch checked={state.gilad} onChange={handleChange} name="gilad" />
}
label="Gilad Gray"
/>
<FormControlLabel
control={
<Switch checked={state.jason} onChange={handleChange} name="jason" />
}
label="Jason Killian"
/>
<FormControlLabel
control={
<Switch checked={state.antoine} onChange={handleChange} name="antoine" />
}
label="Antoine Llorca"
/>
</FormGroup>
<FormHelperText>Be careful</FormHelperText>
</FormControl>
);
}
Customization
Here are some examples of customizing the component. You can learn more about this in the overrides documentation page.
Off
On
import { styled } from '@mui/material/styles';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
import type { SwitchProps } from '@mui/material/Switch';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
const MaterialUISwitch = styled(Switch)(({ theme }) => ({
width: 62,
height: 34,
padding: 7,
'& .MuiSwitch-switchBase': {
margin: 1,
padding: 0,
transform: 'translateX(6px)',
'&.Mui-checked': {
color: '#fff',
transform: 'translateX(22px)',
'& .MuiSwitch-thumb:before': {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 20 20"><path fill="${encodeURIComponent(
'#fff',
)}" d="M4.2 2.5l-.7 1.8-1.8.7 1.8.7.7 1.8.6-1.8L6.7 5l-1.9-.7-.6-1.8zm15 8.3a6.7 6.7 0 11-6.6-6.6 5.8 5.8 0 006.6 6.6z"/></svg>')`,
},
'& + .MuiSwitch-track': {
opacity: 1,
backgroundColor: '#aab4be',
...theme.applyStyles('dark', {
backgroundColor: '#8796A5',
}),
},
},
},
'& .MuiSwitch-thumb': {
backgroundColor: '#001e3c',
width: 32,
height: 32,
'&::before': {
content: "''",
position: 'absolute',
width: '100%',
height: '100%',
left: 0,
top: 0,
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 20 20"><path fill="${encodeURIComponent(
'#fff',
)}" d="M9.305 1.667V3.75h1.389V1.667h-1.39zm-4.707 1.95l-.982.982L5.09 6.072l.982-.982-1.473-1.473zm10.802 0L13.927 5.09l.982.982 1.473-1.473-.982-.982zM10 5.139a4.872 4.872 0 00-4.862 4.86A4.872 4.872 0 0010 14.862 4.872 4.872 0 0014.86 10 4.872 4.872 0 0010 5.139zm0 1.389A3.462 3.462 0 0113.471 10a3.462 3.462 0 01-3.473 3.472A3.462 3.462 0 016.527 10 3.462 3.462 0 0110 6.528zM1.665 9.305v1.39h2.083v-1.39H1.666zm14.583 0v1.39h2.084v-1.39h-2.084zM5.09 13.928L3.616 15.4l.982.982 1.473-1.473-.982-.982zm9.82 0l-.982.982 1.473 1.473.982-.982-1.473-1.473zM9.305 16.25v2.083h1.389V16.25h-1.39z"/></svg>')`,
},
...theme.applyStyles('dark', {
backgroundColor: '#003892',
}),
},
'& .MuiSwitch-track': {
opacity: 1,
backgroundColor: '#aab4be',
borderRadius: 20 / 2,
...theme.applyStyles('dark', {
backgroundColor: '#8796A5',
}),
},
}));
const Android12Switch = styled(Switch)(({ theme }) => ({
padding: 8,
'& .MuiSwitch-track': {
borderRadius: 22 / 2,
'&::before, &::after': {
content: '""',
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
width: 16,
height: 16,
},
'&::before': {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 24 24"><path fill="${encodeURIComponent(
theme.palette.getContrastText(theme.palette.primary.main),
)}" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"/></svg>')`,
left: 12,
},
'&::after': {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 24 24"><path fill="${encodeURIComponent(
theme.palette.getContrastText(theme.palette.primary.main),
)}" d="M19,13H5V11H19V13Z" /></svg>')`,
right: 12,
},
},
'& .MuiSwitch-thumb': {
boxShadow: 'none',
width: 16,
height: 16,
margin: 2,
},
}));
const IOSSwitch = styled((props: SwitchProps) => (
<Switch focusVisibleClassName=".Mui-focusVisible" disableRipple {...props} />
))(({ theme }) => ({
width: 42,
height: 26,
padding: 0,
'& .MuiSwitch-switchBase': {
padding: 0,
margin: 2,
transitionDuration: '300ms',
'&.Mui-checked': {
transform: 'translateX(16px)',
color: '#fff',
'& + .MuiSwitch-track': {
backgroundColor: '#65C466',
opacity: 1,
border: 0,
...theme.applyStyles('dark', {
backgroundColor: '#2ECA45',
}),
},
'&.Mui-disabled + .MuiSwitch-track': {
opacity: 0.5,
},
},
'&.Mui-focusVisible .MuiSwitch-thumb': {
color: '#33cf4d',
border: '6px solid #fff',
},
'&.Mui-disabled .MuiSwitch-thumb': {
color: theme.palette.grey[100],
...theme.applyStyles('dark', {
color: theme.palette.grey[600],
}),
},
'&.Mui-disabled + .MuiSwitch-track': {
opacity: 0.7,
...theme.applyStyles('dark', {
opacity: 0.3,
}),
},
},
'& .MuiSwitch-thumb': {
boxSizing: 'border-box',
width: 22,
height: 22,
},
'& .MuiSwitch-track': {
borderRadius: 26 / 2,
backgroundColor: '#E9E9EA',
opacity: 1,
transition: theme.transitions.create(['background-color'], {
duration: 500,
}),
...theme.applyStyles('dark', {
backgroundColor: '#39393D',
}),
},
}));
const AntSwitch = styled(Switch)(({ theme }) => ({
width: 28,
height: 16,
padding: 0,
display: 'flex',
'&:active': {
'& .MuiSwitch-thumb': {
width: 15,
},
'& .MuiSwitch-switchBase.Mui-checked': {
transform: 'translateX(9px)',
},
},
'& .MuiSwitch-switchBase': {
padding: 2,
'&.Mui-checked': {
transform: 'translateX(12px)',
color: '#fff',
'& + .MuiSwitch-track': {
opacity: 1,
backgroundColor: '#1890ff',
...theme.applyStyles('dark', {
backgroundColor: '#177ddc',
}),
},
},
},
'& .MuiSwitch-thumb': {
boxShadow: '0 2px 4px 0 rgb(0 35 11 / 20%)',
width: 12,
height: 12,
borderRadius: 6,
transition: theme.transitions.create(['width'], {
duration: 200,
}),
},
'& .MuiSwitch-track': {
borderRadius: 16 / 2,
opacity: 1,
backgroundColor: 'rgba(0,0,0,.25)',
boxSizing: 'border-box',
...theme.applyStyles('dark', {
backgroundColor: 'rgba(255,255,255,.35)',
}),
},
}));
export default function CustomizedSwitches() {
return (
<FormGroup>
<FormControlLabel
control={<MaterialUISwitch sx={{ m: 1 }} defaultChecked />}
label="MUI switch"
/>
<FormControlLabel
control={<Android12Switch defaultChecked />}
label="Android 12"
/>
<FormControlLabel
control={<IOSSwitch sx={{ m: 1 }} defaultChecked />}
label="iOS style"
/>
<Stack direction="row" spacing={1} sx={{ alignItems: 'center' }}>
<Typography>Off</Typography>
<AntSwitch
defaultChecked
slotProps={{ input: { 'aria-label': 'ant design' } }}
/>
<Typography>On</Typography>
</Stack>
</FormGroup>
);
}
🎨 If you are looking for inspiration, you can check MUI Treasury's customization examples.
Label placement
You can change the placement of the label:
import Switch from '@mui/material/Switch';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormControl from '@mui/material/FormControl';
import FormLabel from '@mui/material/FormLabel';
export default function FormControlLabelPosition() {
return (
<FormControl component="fieldset">
<FormLabel component="legend">Label placement</FormLabel>
<FormGroup aria-label="position" row>
<FormControlLabel
value="bottom"
control={<Switch color="primary" />}
label="Bottom"
labelPlacement="bottom"
/>
<FormControlLabel
value="end"
control={<Switch color="primary" />}
label="End"
labelPlacement="end"
/>
</FormGroup>
</FormControl>
);
}
When to use
Accessibility
- All form controls should have labels, and this includes radio buttons, checkboxes, and switches. In most cases, this is done by using the
<label>element (FormControlLabel). - When a label can't be used, it's necessary to add an attribute directly to the input component.
In this case, you can apply the additional attribute (for example
aria-label,aria-labelledby,title) via theslotProps.inputprop.
<Switch value="checkedA" slotProps={{ input: { 'aria-label': 'Switch A' } }} />
API
See the documentation below for a complete reference to all of the props and classes available to the components mentioned here.