Skip to contents
This page is an adaptation of the related MUI Material UI documentation page.

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.

Basic switches

JS code
import * as React from 'react';
import Switch from '@mui/material/Switch';

const label = { inputProps: { 'aria-label': 'Switch demo' } };

export default function BasicSwitches() {
  return (
    <div>
      <Switch {...label} defaultChecked />
      <Switch {...label} />
      <Switch {...label} disabled defaultChecked />
      <Switch {...label} disabled />
    </div>
  );
}
library(shiny)

ui <- shinyMaterialUIPage(
  div(
    Switch.shinyInput(
      inputId = "switch1",
      value = TRUE,
      inputProps = list('aria-label' = 'Switch demo')
    ),
    Switch.shinyInput(
      inputId = "switch2",
      value = FALSE,
      inputProps = list('aria-label' = 'Switch demo')
    ),
    Switch.shinyInput(
      inputId = "switch3",
      value = TRUE,
      disabled = TRUE,
      inputProps = list('aria-label' = 'Switch demo')
    ),
    Switch.shinyInput(
      inputId = "switch4",
      value = FALSE,
      disabled = TRUE,
      inputProps = list('aria-label' = 'Switch demo')
    )
  )
)

server <- function(input, output, session) {
  # Access switch values with input$switch1, input$switch2, etc.
}

shinyApp(ui, server)

Label

You can provide a label to the Switch thanks to the FormControlLabel component.

JS code
import * as React from 'react';
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>
  );
}
library(shiny)

ui <- shinyMaterialUIPage(
  FormGroup(
    FormControlLabel(
      control = Switch.shinyInput(
        inputId = "labeled-switch1",
        value = TRUE
      ),
      label = "Label"
    ),
    FormControlLabel(
      required = TRUE,
      control = Switch.shinyInput(
        inputId = "labeled-switch2",
        value = FALSE
      ),
      label = "Required"
    ),
    FormControlLabel(
      disabled = TRUE,
      control = Switch.shinyInput(
        inputId = "labeled-switch3",
        value = FALSE
      ),
      label = "Disabled"
    )
  )
)

server <- function(input, output, session) {
  # Handle switch states
}

shinyApp(ui, server)

Size

Use the size prop to change the size of the switch.

JS code
import * as React from 'react';
import Switch from '@mui/material/Switch';

const label = { inputProps: { 'aria-label': 'Size switch demo' } };

export default function SwitchesSize() {
  return (
    <div>
      <Switch {...label} defaultChecked size="small" />
      <Switch {...label} defaultChecked />
    </div>
  );
}
library(shiny)

ui <- function() {
  CssBaseline(
    div(
      Switch.shinyInput(
        inputId = "size-switch-small",
        value = TRUE,
        size = "small",
        inputProps = list('aria-label' = 'Size switch demo')
      ),
      Switch.shinyInput(
        inputId = "size-switch-medium",
        value = TRUE,
        inputProps = list('aria-label' = 'Size switch demo')
      )
    )
  )
}

server <- function(input, output, session) {
  
}

shinyApp(ui, server)

Color

JS code
import * as React from 'react';
import { pink } from '@mui/material/colors';
import Switch from '@mui/material/Switch';

const label = { inputProps: { 'aria-label': '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" />
      <Switch
        {...label}
        defaultChecked
        sx={{
          '& .MuiSwitch-switchBase.Mui-checked': {
            color: pink[600],
            '&:hover': {
              backgroundColor: alpha(pink[600], 0.08),
            },
          },
          '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': {
            backgroundColor: pink[600],
          },
        }}
      />
    </div>
  );
}
library(shiny)

ui <- function() {
  CssBaseline(
    div(
      Switch.shinyInput(
        inputId = "color-switch-primary",
        value = TRUE,
        inputProps = list('aria-label' = 'Switch demo')
      ),
      Switch.shinyInput(
        inputId = "color-switch-secondary",
        value = TRUE,
        color = "secondary",
        inputProps = list('aria-label' = 'Switch demo')
      ),
      Switch.shinyInput(
        inputId = "color-switch-warning",
        value = TRUE,
        color = "warning",
        inputProps = list('aria-label' = 'Switch demo')
      ),
      Switch.shinyInput(
        inputId = "color-switch-default",
        value = TRUE,
        color = "default",
        inputProps = list('aria-label' = 'Switch demo')
      ),
      Switch.shinyInput(
        inputId = "color-switch-custom",
        value = TRUE,
        sx = list(
          '& .MuiSwitch-switchBase.Mui-checked' = list(
            color = '#e91e63',
            '&:hover' = list(
              backgroundColor = 'rgba(233, 30, 99, 0.08)'
            )
          ),
          '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track' = list(
            backgroundColor = '#e91e63'
          )
        ),
        inputProps = list('aria-label' = 'Switch demo')
      )
    )
  )
}

server <- function(input, output, session) {
  
}

shinyApp(ui, server)

Controlled

You can control the switch with the checked and onChange props:

JS code
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}
      inputProps={{ 'aria-label': 'controlled' }}
    />
  );
}
library(shiny)

ui <- shinyMaterialUIPage(
  Switch.shinyInput(
    inputId = "controlled-switch",
    value = TRUE,
    inputProps = list('aria-label' = 'controlled')
  ),
  br(),
  textOutput("switch_state")
)

server <- function(input, output, session) {
  output$switch_state <- renderText({
    paste("Switch is:", if(input$`controlled-switch`) "ON" else "OFF")
  })
}

shinyApp(ui, server)

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).

JS code
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>
  );
}
library(shiny)

ui <- shinyMaterialUIPage(
  FormControl(
    component = "fieldset",
    variant = "standard",
    FormLabel(component = "legend", "Assign responsibility"),
    FormGroup(
      FormControlLabel(
        control = Switch.shinyInput(
          inputId = "gilad",
          value = TRUE
        ),
        label = "Gilad Gray"
      ),
      FormControlLabel(
        control = Switch.shinyInput(
          inputId = "jason",
          value = FALSE
        ),
        label = "Jason Killian"
      ),
      FormControlLabel(
        control = Switch.shinyInput(
          inputId = "antoine",
          value = TRUE
        ),
        label = "Antoine Llorca"
      )
    ),
    FormHelperText("Be careful")
  ),
  br(),
  h4("Current states:"),
  textOutput("group_states")
)

server <- function(input, output, session) {
  output$group_states <- renderText({
    paste(
      "Gilad:", input$gilad,
      "| Jason:", input$jason,
      "| Antoine:", input$antoine
    )
  })
}

shinyApp(ui, server)

Customization

Here are some examples of customizing the component. You can learn more about this in the overrides documentation page.

JS code
import * as React from 'react';
import { styled } from '@mui/material/styles';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch, { SwitchProps } from '@mui/material/Switch';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';

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,
      },
      '&.Mui-disabled + .MuiSwitch-track': {
        opacity: 0.5,
      },
    },
    '&.Mui-focusVisible .MuiSwitch-thumb': {
      color: '#33cf4d',
      border: '6px solid #fff',
    },
    '&.Mui-disabled .MuiSwitch-thumb': {
      color: theme.palette.mode === 'light'
        ? theme.palette.grey[100]
        : theme.palette.grey[600],
    },
    '&.Mui-disabled + .MuiSwitch-track': {
      opacity: theme.palette.mode === 'light' ? 0.7 : 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,
    }),
  },
}));

export default function CustomizedSwitches() {
  return (
    <FormGroup>
      <FormControlLabel
        control={<IOSSwitch sx={{ m: 1 }} defaultChecked />}
        label="iOS style"
      />
    </FormGroup>
  );
}
library(shiny)

ui <- function() {
  CssBaseline(
    ThemeProvider(
      theme = list(
        components = list(
          MuiSwitch = list(
            styleOverrides = list(
              root = list(
                "&.ios-switch" = list(
                  width = 42,
                  height = 26,
                  padding = 0,
                  '& .MuiSwitch-switchBase' = list(
                    padding = 0,
                    margin = 2,
                    transitionDuration = '300ms',
                    '&.Mui-checked' = list(
                      transform = 'translateX(16px)',
                      color = '#fff',
                      '& + .MuiSwitch-track' = list(
                        backgroundColor = '#65C466',
                        opacity = 1,
                        border = 0
                      ),
                      '&.Mui-disabled + .MuiSwitch-track' = list(
                        opacity = 0.5
                      )
                    ),
                    '&.Mui-focusVisible .MuiSwitch-thumb' = list(
                      color = '#33cf4d',
                      border = '6px solid #fff'
                    ),
                    '&.Mui-disabled .MuiSwitch-thumb' = list(
                      color = '#f5f5f5'
                    ),
                    '&.Mui-disabled + .MuiSwitch-track' = list(
                      opacity = 0.7
                    )
                  ),
                  '& .MuiSwitch-thumb' = list(
                    boxSizing = 'border-box',
                    width = 22,
                    height = 22
                  ),
                  '& .MuiSwitch-track' = list(
                    borderRadius = 13,
                    backgroundColor = '#E9E9EA',
                    opacity = 1,
                    transition = 'background-color 500ms'
                  )
                )
              )
            )
          )
        )
      ),
      FormGroup(
        FormControlLabel(
          control = Switch.shinyInput(
            inputId = "ios-switch",
            value = TRUE,
            className = "ios-switch",
            sx = list(m = 1),
            disableRipple = TRUE
          ),
          label = "iOS style"
        )
      )
    )
  )
}

server <- function(input, output, session) {
  
}

shinyApp(ui, server)

🎨 If you are looking for inspiration, you can check MUI Treasury’s customization examples.

Label placement

You can change the placement of the label:

JS code
import * as React from 'react';
import Switch from '@mui/material/Switch';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';

export default function FormControlLabelPosition() {
  return (
    <FormGroup aria-label="position" row>
      <FormControlLabel
        value="top"
        control={<Switch color="primary" />}
        label="Top"
        labelPlacement="top"
      />
      <FormControlLabel
        value="start"
        control={<Switch color="primary" />}
        label="Start"
        labelPlacement="start"
      />
      <FormControlLabel
        value="bottom"
        control={<Switch color="primary" />}
        label="Bottom"
        labelPlacement="bottom"
      />
      <FormControlLabel
        value="end"
        control={<Switch color="primary" />}
        label="End"
        labelPlacement="end"
      />
    </FormGroup>
  );
}
library(shiny)

ui <- function() {
  CssBaseline(
    FormGroup(
      "aria-label" = "position",
      row = TRUE,
      FormControlLabel(
        value = "top",
        control = Switch.shinyInput(
          inputId = "switch-top",
          value = FALSE,
          color = "primary"
        ),
        label = "Top",
        labelPlacement = "top"
      ),
      FormControlLabel(
        value = "start",
        control = Switch.shinyInput(
          inputId = "switch-start",
          value = FALSE,
          color = "primary"
        ),
        label = "Start",
        labelPlacement = "start"
      ),
      FormControlLabel(
        value = "bottom",
        control = Switch.shinyInput(
          inputId = "switch-bottom",
          value = FALSE,
          color = "primary"
        ),
        label = "Bottom",
        labelPlacement = "bottom"
      ),
      FormControlLabel(
        value = "end",
        control = Switch.shinyInput(
          inputId = "switch-end",
          value = FALSE,
          color = "primary"
        ),
        label = "End",
        labelPlacement = "end"
      )
    )
  )
}

server <- function(input, output, session) {
  
}

shinyApp(ui, server)

Accessibility

  • It will render an element with the checkbox role not switch role since this role isn’t widely supported yet. Please test first if assistive technology of your target audience supports this role properly. Then you can change the role with <Switch inputProps={{ role: 'switch' }}>
  • 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 the inputProps prop.
JS code
<Switch value="checkedA" inputProps={{ 'aria-label': 'Switch A' }} />
library(shiny)

AccessibleSwitch <- function() {
  CssBaseline(
    Switch.shinyInput(
      inputId = "accessible-switch",
      value = FALSE,
      inputProps = list('aria-label' = 'Switch A')
    )
  )
}