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

Material UI自定义Classic主题切换失效问题求助

问题

我用Material UI创建了dark、classic、light三种主题模式,在Home.js中通过按钮切换。Dark和Light按钮切换正常,但点击Classic按钮时应用崩溃,控制台报两个错误:

  • MUI: The palette mode 'classic' is not supported.
  • ERROR Cannot read properties of undefined (reading 'primary')

相关代码如下:

theme.js

import { createTheme } from "@mui/material";
import { createContext, useMemo, useState } from "react";

export const tokens = (mode) => ({
  ...(mode === "dark"
    ? {
        // DARK MODE
        primary1: {
          500: "#1E2230",
        },

        primary2: {
          500: "#171A25",
        },

        primary3: {
          500: "#242937",
        },
        button: {
          main: "#3555FF",
        },
      }
    : mode === "classic"
    ? {
        // CLASSIC MODE
        primary1: {
          500: "#211839",
        },
        primary2: {
          500: "#150D29",
        },
        primary3: {
          500: "#211839",
        },
      }
    : // LIGHT MODE
      {
        primary1: {
          100: "#040507",
          200: "#090a0e",
          300: "#0d0e15",
          400: "#12131c",
          500: "#161823",
          600: "#45464f",
          700: "#73747b",
          800: "#a2a3a7",
          900: "#d0d1d3",
        },

        primary2: {
          100: "#06070a",
          200: "#0c0e13",
          300: "#12141d",
          400: "#181b26",
          500: "#1e2230",
          600: "#4b4e59",
          700: "#787a83",
          800: "#a5a7ac",
          900: "#d2d3d6",
        },

        primary3: {
          100: "#07080b",
          200: "#0e1016",
          300: "#161921",
          400: "#1d212c",
          500: "#242937",
          600: "#50545f",
          700: "#7c7f87",
          800: "#a7a9af",
          900: "#d3d4d7",
        },
      }),
});

const DARK_MODE_BACKGROUND = "#131017";
// const CLASSIC_MODE_BACKGROUND = "#16121C";
const CLASSIC_MODE_BACKGROUND = "red";
const LIGHT_MODE_BACKGROUND = "white";

export const themeSettings = (mode) => {
  const colors = tokens(mode);
  return {
    palette: {
      mode: mode,
      ...(mode === "dark"
        ? {
            primary: {
              main: colors.primary1[500],
            },
            secondary: {
              main: colors.primary2[500],
            },
            background: {
              default: DARK_MODE_BACKGROUND,
            },
          }
        : mode === "classic"
        ? {
            primary: {
              main: colors.primary1[500],
            },
            secondary: {
              main: colors.primary2[500],
            },
            background: {
              default: CLASSIC_MODE_BACKGROUND,
            },
          }
        : {
            primary: {
              main: colors.primary1[100],
            },
            secondary: {
              main: colors.primary2[100],
            },
            background: {
              default: LIGHT_MODE_BACKGROUND,
            },
          }),
    },
  };
};

// context for color mode
export const ColorModeContext = createContext({
  toggleColorMode: () => {},
});

export const useMode = () => {
  // set the mode
  const [mode, setMode] = useState("dark");
  const colorMode = useMemo(
    () => ({
      toggleColorMode: (mode) => {
        switch (mode) {
          case "dark":
            setMode("dark");
            break;
          case "classic":
            setMode("classic");
            break;
          case "light":
          default:
            setMode("light");
            break;
        }
      },
    }),
    []
  );

  const theme = useMemo(() => createTheme(themeSettings(mode)), [mode]);
  return [theme, colorMode, setMode];
};

Home.js

import { Button, Typography } from "@mui/material";
import React, { useContext } from "react";
import { ColorModeContext, tokens } from "../Theme";
import { useTheme } from "@emotion/react";

export default function Home() {
  const theme = useTheme();
  const colors = tokens(theme.palette.mode);
  const colorMode = useContext(ColorModeContext);

  return (
    <div>
      hi
      <Button
        onClick={() => colorMode.toggleColorMode("dark")}
        variant="contained"
      >
        Dark
      </Button>
      <Button
        onClick={() => colorMode.toggleColorMode("classic")}
        variant="contained"
      >
        Classic
      </Button>
      <Button
        onClick={() => colorMode.toggleColorMode("light")}
        variant="contained"
      >
        Light
      </Button>
      <Typography variant="h1" color="primary"></Typography>
    </div>
  );
}

问题原因

  1. MUI palette模式限制:Material UI的palette.mode仅支持官方定义的dark和light两种值,自定义的classic不在支持范围内,触发第一个报错的同时会导致MUI内部主题逻辑异常。
  2. 主题字段缺失:Classic模式的tokens中缺少button字段,而contained类型的Button组件会尝试读取theme.palette.button.main,该字段不存在时会抛出“读取undefined属性”的错误。

修复方案

步骤1:修正palette.mode的值

将Classic模式的palette.mode设为dark(因Classic属于深色系主题),规避MUI的模式校验,同时通过自定义颜色区分Classic和Dark模式。

步骤2:补全Classic模式的tokens字段

在Classic模式的tokens中添加button字段,确保组件能读取到所需颜色值。

修改后的关键代码片段

theme.js(修改部分)

// 补全Classic模式的button字段
export const tokens = (mode) => ({
  ...(mode === "dark"
    ? { /* 原Dark模式代码不变 */ }
    : mode === "classic"
    ? {
        // CLASSIC MODE
        primary1: {
          500: "#211839",
        },
        primary2: {
          500: "#150D29",
        },
        primary3: {
          500: "#211839",
        },
        // 添加button字段,适配contained按钮
        button: {
          main: "#6A4C93", // 自定义Classic模式按钮颜色
        },
      }
    : /* 原Light模式代码不变 */),
});

// 修正Classic模式的palette.mode为dark
export const themeSettings = (mode) => {
  const colors = tokens(mode);
  return {
    palette: {
      // 对classic模式使用dark作为基础mode
      mode: mode === "classic" ? "dark" : mode,
      ...(mode === "dark"
        ? { /* 原Dark模式代码不变 */ }
        : mode === "classic"
        ? {
            primary: {
              main: colors.primary1[500],
            },
            secondary: {
              main: colors.primary2[500],
            },
            background: {
              default: CLASSIC_MODE_BACKGROUND,
            },
          }
        : /* 原Light模式代码不变 */),
    },
  };
};

额外说明

  • 若需完全自定义主题模式,可通过扩展MUI的主题类型支持自定义mode,适合TypeScript项目。
  • 确保所有组件用到的主题字段在各模式的tokens中均有定义,避免出现undefined读取错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 23:02:30