PCロール

PCロール

【Material UI】カラーパレット・ダークテーマ実装の覚書

【Material UI】カラーパレット・ダークテーマ実装の覚書

この記事は、Gajeroll Advent Calendar 2022 の 19 日目の記事です。

はじめに

みんな大好き、Material UI。この記事では、Material UI を使う際のテーマ設定の方法を紹介します。

Material UI とは

Material UI は Material Design を実装したもの

Material UI is a library of React UI components that implements Google's Material Design.

引用: Overview - Material UI

Google の Material Design は 2014 年に初めてリリースされ、2021 年、最新の Material Design 3 が発表されました。Material UI v5 では、1 世代前の Material Design 2 が実装されています。

2021 年に名称が変更

Material UI?Material Design?MUI?似たような名詞が複数ありますが、現在は以下のようになっています。

Starting today we are evolving our brand identity to clarifying the difference between our company and our products.

  • Material UI: the organization is now called MUI.
  • Material UI: the set of foundational MIT React components is now called MUI Core.
  • Material UI: the Material Design components developed by MUI. Also, we ditched the hyphen!
  • Material UI X: the set of advanced React components is now called MUI X. Our previous name was no longer serving our areas of focus. We have grown our product offering. We needed a new identity to match our increased scope.

引用: Material UI is now MUI! - MUI

Material Design は先述の通り、Google のデザインシステムです。

カラーパレットをカスタマイズする

現行の Material UI は M2 が実装されているため、デフォルトのカラーシステムも M2 に準拠します。カラーパレットをカスタマイズするためには、createTheme 関数と ThemeProvider (コンポーネント)を使います。

createTheme 関数

createTheme 関数は、引数として options をとり、その options に基づいて、テーマを生成します。戻り値を後述の ThemeProvider の prop として渡します。

ThemeProvider

prop としてテーマをとり、ラップしているコンポーネントにテーマを適用します。App.jsx 等のルートに近いところで使うイメージです。

import * as React from "react";
import { red } from "@mui/material/colors";
import { ThemeProvider, createTheme } from "@mui/material/styles";

const theme = createTheme({
  palette: {
    primary: {
      main: red[500],
    },
  },
});

function App() {
  return <ThemeProvider theme={theme}>...</ThemeProvider>;
}

参照: Theming - Material UI

ちなみに、Material Design 2 に準拠するカラーテーマを作りたい場合は、こちらの公式のツールが利用できます。

Material Design 2 カラーツール

ダークモードに対応する

アプリケーションのテーマをダークテーマにするには、 createThemepalettemodedark に設定すればよいです。

import { ThemeProvider, createTheme } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";

const darkTheme = createTheme({
  palette: {
    mode: "dark",
  },
});

function App() {
  return (
    <ThemeProvider theme={darkTheme}>
     

 <CssBaseline />
      <main>This app is using the dark mode</main>
    </ThemeProvider>
  );
}

export default App;

参照: Dark mode - Material UI

ライト・ダークでカラーパレットを変える

前項の方法では、常にダークテーマで表示されてしまいます。ライト・ダークのテーマに応じて異なるカラーパレットを使うには、以下のように、モードを引数にとってオプションのオブジェクトを返す関数を用意します。

const getDesignTokens = (mode: PaletteMode) => ({
  palette: {
    mode,
    ...(mode === "light"
      ? {
          // palette values for light mode
          primary: amber,
          secondary: amber[200],
        }
      : {
          // palette values for dark mode
          primary: deepOrange,
          secondary: deepOrange[700],
        }),
  },
});

引用元: Dark mode - Material UI

ライト・ダークを切り替え

ライト・ダークでテーマの切り替えは、カラーパレットの mode を変更することで実現できます。React のフックを使えば容易に実装できるでしょう。以下は、公式ドキュメント内のコード例を引用しています。

import * as React from "react";
import IconButton from "@mui/material/IconButton";
import Box from "@mui/material/Box";
import { useTheme, ThemeProvider, createTheme } from "@mui/material/styles";
import Brightness4Icon from "@mui/icons-material/Brightness4";
import Brightness7Icon from "@mui/icons-material/Brightness7";

const ColorModeContext = React.createContext({ toggleColorMode: () => {} });

function MyApp() {
  const theme = useTheme();
  const colorMode = React.useContext(ColorModeContext);
  return (
    <Box
      sx={{
        display: "flex",
        width: "100%",
        alignItems: "center",
        justifyContent: "center",
        bgcolor: "background.default",
        color: "text.primary",
        borderRadius: 1,
        p: 3,
      }}
    >
      {theme.palette.mode} mode
      <IconButton
        sx={{ ml: 1 }}
        onClick={colorMode.toggleColorMode}
        color="inherit"
      >
        {theme.palette.mode === "dark" ? (
          <Brightness7Icon />
        ) : (
          <Brightness4Icon />
        )}
      </IconButton>
    </Box>
  );
}

export default function ToggleColorMode() {
  const [mode, setMode] = React.useState("light");
  const colorMode is React.useMemo(
    () => ({
      toggleColorMode: () => {
        setMode((prevMode) => (prevMode === "light" ? "dark" : "light"));
      },
    }),
    []
  );

  const theme is React.useMemo(
    () =>
      createTheme({
        palette: {
          mode,
        },
      }),
    [mode]
  );

  return (
    <ColorModeContext.Provider value={colorMode}>
      <ThemeProvider theme={theme}>
        <MyApp />
      </ThemeProvider>
    </ColorModeContext.Provider>
  );
}

引用: Dark mode - Material UI

デバイスのテーマ設定を使う

デフォルトのカラーテーマを OS のテーマに合わせるには、useMediaQuery という API を使います。 useMediaQuery は引数で渡した CSS メディアクエリが正しいかどうかの真偽値を返します。 この関数の引数として、ユーザーのシステムのカラーテーマがダークテーマであるという旨の (prefers-color-scheme: dark)') を指定すれば、ダークモードの場合には true、そうでない場合には false を返します。

import * as React from "react";
import useMediaQuery from "@mui/material/useMediaQuery";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";

function App() {
  const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");

  const theme = React.useMemo(
    () =>
      createTheme({
        palette: {
          mode: prefersDarkMode ? "dark" : "light",
        },
      }),
    [prefersDarkMode]
  );

  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Routes />
    </ThemeProvider>
  );
}

引用: Dark mode - Material UI

おわりに

最後までご覧いただきありがとうございます。 PC ロールでは、テクノロジーに関する情報をまとめて発信しています。 また、おすすめのガジェットについて幅広く紹介していく、ガジェロールもあります。 ガジェットやソフトを使うエンジニア・クリエイターはぜひご覧ください。