You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将MUI 5 Switch自定义为双标签切换开关?

MUI 5 Switch 双标签自定义问题解决

需求说明

  • 开关总长140px,“A”“B”两侧各占70px,标签始终可见;
  • 选中“A”时,“A”侧为主题主色背景+白色文字,“B”侧为白色背景+黑色文字,切换后互换配色;
  • 完全隐藏开关的thumb(包括hover和点击状态)。

当前实现代码

import { styled } from "@mui/material/styles";
import Switch, { SwitchProps } from "@mui/material/Switch";

const App = styled(Switch)<SwitchProps>(({ theme }) => ({
  width: "140px",
  height: "42px",
  padding: 0,
  border: "1px solid #C6CBD0",
  borderRadius: "9px",

  "& .MuiSwitch-switchBase": {
    transition: theme.transitions.create(["transform", "background-color"], {
      duration: theme.transitions.duration.shortest,
    }),

    "&.Mui-checked": {
      transform: "translateX(70px)",
    },

    "&.Mui-checked + .MuiSwitch-track": {
      backgroundColor: theme.palette.secondary.main,
      opacity: 1,
      display: "flex",
      alignItems: "center",
      justifyContent: "flex-end",

      "&:before": {
        content: '"B"',
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        fontWeight: 700,
        fontSize: "20px",
        width: "50%",
        color: theme.palette.getContrastText(theme.palette.secondary.main),
      },
    },

    "&.Mui-checked + .MuiSwitch-track.Mui-disabled": {
      backgroundColor: theme.palette.grey[400],
    },
  },

  "& .MuiSwitch-thumb": {
    width: "70px",
    height: "42px",
    opacity: 0,
  },

  "& .MuiSwitch-track": {
    backgroundColor: theme.palette.primary.main,
    opacity: 1,
    display: "flex",
    alignItems: "center",
    justifyContent: "flex-start",

    "&:before": {
      content: "'A'",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      fontWeight: 700,
      fontSize: "20px",
      width: "50%",
      color: theme.palette.getContrastText(theme.palette.primary.main),
    },
  },

  "&.Mui-disabled": {
    "& .MuiSwitch-switchBase": {
      backgroundColor: theme.palette.grey[400],
    },
  },
}));

export default App;

修正方案与代码

核心调整点

  1. 双标签持久显示:给MuiSwitch-track添加:before和:after两个伪元素,分别固定显示“A”和“B”,各自占据50%宽度;
  2. 背景色切换逻辑:让MuiSwitch-switchBase作为可滑动的背景块,选中时通过平移覆盖对应侧,track保持白色背景,通过伪元素颜色区分选中状态;
  3. 彻底隐藏thumb:给thumb添加pointerEvents: 'none',同时设置switchBase的尺寸与单侧一致,避免交互干扰。

修正后的代码

import { styled } from "@mui/material/styles";
import Switch, { SwitchProps } from "@mui/material/Switch";

const CustomToggleSwitch = styled(Switch)<SwitchProps>(({ theme }) => ({
  width: 140,
  height: 42,
  padding: 0,
  border: "1px solid #C6CBD0",
  borderRadius: 9,
  position: "relative",

  "& .MuiSwitch-switchBase": {
    width: 70,
    height: 40,
    margin: 0,
    transition: theme.transitions.create("transform", {
      duration: theme.transitions.duration.shortest,
    }),
    backgroundColor: theme.palette.primary.main,
    borderRadius: 8,

    "&.Mui-checked": {
      transform: "translateX(70px)",
      backgroundColor: theme.palette.secondary.main,
    },

    "&.Mui-disabled": {
      backgroundColor: theme.palette.grey[400],
    },
  },

  "& .MuiSwitch-thumb": {
    width: 0,
    height: 0,
    opacity: 0,
    pointerEvents: "none",
  },

  "& .MuiSwitch-track": {
    width: "100%",
    height: "100%",
    backgroundColor: "#fff",
    opacity: 1,
    display: "flex",
    alignItems: "center",
    justifyContent: "space-around",
    position: "relative",

    "&:before, &:after": {
      content: '""',
      position: "absolute",
      width: "50%",
      height: "100%",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      fontWeight: 700,
      fontSize: 20,
      zIndex: 1,
    },

    "&:before": {
      content: '"A"',
      left: 0,
      color: ({ ownerState }) =>
        ownerState.checked ? "#000" : theme.palette.getContrastText(theme.palette.primary.main),
    },

    "&:after": {
      content: '"B"',
      right: 0,
      color: ({ ownerState }) =>
        ownerState.checked ? theme.palette.getContrastText(theme.palette.secondary.main) : "#000",
    },
  },

  "&.Mui-disabled": {
    opacity: 0.6,
    borderColor: theme.palette.grey[300],

    "& .MuiSwitch-track:before, & .MuiSwitch-track:after": {
      color: theme.palette.grey[500],
    },
  },
}));

export default CustomToggleSwitch;

效果说明

  • 开关总宽度140px,两侧各70px,“A”“B”标签始终可见;
  • 未选中时,“A”侧为主题主色背景+白色文字,“B”侧白色背景+黑色文字;
  • 选中后,“B”侧变为主题次色背景+白色文字,“A”侧白色背景+黑色文字;
  • thumb完全隐藏,无任何hover/点击时的交互痕迹。

内容的提问来源于stack exchange,提问作者Tigran Petrosyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 21:27:05