Brian
Brian

Reputation: 1808

Customize material UI Switch when checked and disabled

I'm having trouble adding the styling to a Material UI Switch in React when it is disabled. I'd like to use withStyles for this. The handling for the checked vs unchecked states works fine as does the styling for the track, but nothing I've tried has worked to style the disabled state of either the thumb or the track.

Here's the code I'm using including some commented out attempts to style the disabled state:

const MySwitch = withStyles({
    switchBase: {
        color: "orange",
        opacity: 0.8,
        "&$checked": {
            color: "orange",
            opacity: 1
        },
        "&$checked + $track": {
            backgroundColor: "black",
            opacity: 1
        },
        // "&$checked + $disabled": {
        //     color: "gray",
        //     opacity: 1
        // },
        // "&disabled": {
        //     color: "gray",
        //     opacity: 1
        // },
        // "&:disabled": {
        //     color: "gray",
        //     opacity: 1
        // },
    },
    // disabled: {
    //     "& + $thumb": {
    //         color: "gray"
    //     }
    // },
    checked: {},
    track: {}
})(Switch); 

Any thoughts?

Upvotes: 3

Views: 12546

Answers (3)

Brian
Brian

Reputation: 1808

Thanks Ryan and Giovanni. Both of your answers contributed to my figuring it out. Key thing from Ryan is that in order to use "&$disabled" in a rule, we need to have "disabled:{}" in there too. And then Giovanni's answer got me thinking about how the disabled states and checked states interact. Here was my code that got disabled to work and was able to style something that was both checked and disabled which was my ultimate goal:

const MySwitch = withStyles({
    switchBase: {
        // thumb when unchecked
        color: "orange",
        opacity: 0.8,
        "&$checked": {
            // thumb when checked
            color: "orange",
            opacity: 1,
            // track when checked
            "& + $track": {
                backgroundColor: "black",
                opacity: 1,
            },
            // The rules above override the default rules for graying 
            // out the thumb and track when the switch is disabled,
            // so we have to add that back in ourselves
            "&$disabled": {
                // gray out the thumb
                color: "#bbb",
                "& + $track": {
                    // gray out the track
                    backgroundColor: "#ddd"
                }
            }
        },
    },
    checked: {},
    track: {},
    disabled: {}
})(Switch);

Upvotes: 1

Ryan Cogswell
Ryan Cogswell

Reputation: 80976

When having difficulty customizing the styles for a particular component, there are two main resources to look at:

  1. The customization examples in the documentation: https://material-ui.com/components/switches/#customized-switches
  2. The default styles in the source code: https://github.com/mui-org/material-ui/blob/v4.12.2/packages/material-ui/src/Switch/Switch.js#L93

The main issue I see with your commented-out attempts are that you didn't use the correct syntax for referring to the disabled state. Within switchBase, you can either use "&$disabled" (which requires that you separately include disabled: {} since $ is used to refer to other style rules declared within the same withStyles call) or "&.Mui-disabled" (leveraging the global class name that $disabled will resolve to). Below is an example of the correct syntax modeled off of the approach used for the default disabled styles (using colors that make it obvious that the customization is working):

import React from "react";
import MuiSwitch from "@material-ui/core/Switch";
import { withStyles } from "@material-ui/core/styles";

const Switch = withStyles({
  switchBase: {
    "&$disabled": {
      color: "yellow"
    },
    "&$disabled + $track": {
      backgroundColor: "green",
      opacity: 0.5
    }
  },
  track: {},
  disabled: {}
})(MuiSwitch);

export default function Switches() {
  return (
    <div>
      <Switch disabled inputProps={{ "aria-label": "disabled checkbox" }} />
      <Switch
        disabled
        checked
        inputProps={{ "aria-label": "primary checkbox" }}
      />
    </div>
  );
}

Edit Switch disabled style


Below is a v5 example leveraging styled:

import React from "react";
import MuiSwitch from "@material-ui/core/Switch";
import { switchClasses } from "@material-ui/core/Switch";
import { styled } from "@material-ui/core/styles";

const Switch = styled(MuiSwitch)(`
  & .${switchClasses.switchBase}.${switchClasses.disabled} {
    color: yellow
  }
  & .${switchClasses.switchBase}.${switchClasses.disabled} + .${switchClasses.track} {
      background-color: green;
      opacity: 0.5
  }
`);

export default function Switches() {
  return (
    <div>
      <Switch disabled inputProps={{ "aria-label": "disabled checkbox" }} />
      <Switch
        disabled
        checked
        inputProps={{ "aria-label": "primary checkbox" }}
      />
    </div>
  );
}

Edit Switch disabled style

Upvotes: 4

Giovanni Esposito
Giovanni Esposito

Reputation: 11156

This happens because when Switch is disabled, css loads .MuiSwitch-colorSecondary.Mui-disabled + .MuiSwitch-track. So you have to override this class if you want to change backgroudColor when Switch is disabled.

So your Switch becomes:

const MySwitch = withStyles({
    switchBase: {
        color: "orange",
        opacity: 0.8,
        "&$checked": {
            color: "orange",
            opacity: 1
        },
        "&$checked + $track": {
            backgroundColor: "black",
            opacity: 1
        },
        "&.MuiSwitch-colorSecondary.Mui-disabled + .MuiSwitch-track": {
            backgroundColor: "black"
        }
    },
    checked: {},
    track: {}
})(Switch); 

Here a codesandbox example.

The result is:

enter image description here

The first one is disabled, the second is enable.

Upvotes: 2

Related Questions