TypeScriptでMUI(Material-UI)のカスタマイズ方法

TypeScriptでMUIをカスタマイズする方法を詳しく知りたい

公式にもカスタマイズする方法が載っているのですが初心者には説明が足りないと感じます

そこでReact+TypeScript環境でMUI(Material-UI)をカスタマイズする方法を詳しく解説します

前提条件
  • Visual Studio Code:1.76.0
  • Node.js:8.15.0

ReactプロジェクトはCreate React Appで作成しており、TypeScriptテンプレートを使用しています

詳しくはこちらの記事を参照してください

目次

テーマ

MUI(Material-UI)にはデフォルトテーマが設定されています

そのテーマをカスタマイズするためにはThemeProviderを使用します

ThemeProviderだけでもカスタマイズできるのですが、CssBaselineをラップしないとBody要素にテーマが適用されません

CssBaselineはリセットCSSと呼ばれており、デフォルトスタイルはブラウザごとにバグや微妙な差があり、この差を調整してくれるのがリセットCSSなのです

まずはデフォルトで設定されているダークモードに変更してみます

function App() {
  const theme = createTheme({
    palette: {
      mode: 'dark',
    },
  });
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <FormControlLabel control={<Checkbox />} label="Label" />
      <Button color="primary" variant="contained">
        primary
      </Button>
    </ThemeProvider>
  );
}
デフォルトとダークモード

試しにCssBaselineを外してみると、配下のCheckboxとButtonには適用されるのですが、Bodyには適用されないのが分かります

スタイル付きコンポーネント

styled()を使用することでスタイル付きのカスタムコンポーネントを作成することもできます

次の例ではCheckboxコンポーネントに対して基本色とchecked状態の色を変更しています

const StyledCheckbox = styled(Checkbox)(({ theme }) => ({
  color: orange[500],
  '&.Mui-checked': {
    color: orange[500],
  },
}));

function CustomCheckbox(props: CheckboxProps) {
  return <StyledCheckbox {...props} />;
}
Checkboxの色変更

MUIではパレットカラーとして赤やオレンジなど19種類が用意されています

500という数字は色相と色合いを表した値で50が最も明るく900が最も暗い色合いになります

&.Mui-checkedの&とは?

&(アンパサンド)とは、SASS(.scss)における親要素(セレクタ)自体を意味します。&.Mui-checkedがCSSにコンパイルされると.css-1hwodmi-MuiButtonBase-root-MuiCheckbox-root.Mui-checkedのようになります

{…props}の…とは?

…変数はJavascriptのスプレッド構文になります。ここでは引数で渡されたpropsのプロパティを展開してStyledCheckboxのプロパティに設定しています

モジュールの拡張

モジュールを拡張する方法を解説します

Color

Buttonの色にはprimaryを指定していますが、primary以外にもsecondary、error、warning、info、successがあります

ですが、実際に開発していくとこれ以外のカラーを使用したくなる場合があります

TypeScriptを使用している場合、モジュールの拡張をしないと次のようにエラーになります

TypeScriptでエラー

今回はモジュール拡張をするのに型定義ファイル (.d.ts)を使用する方法を紹介します

型定義ファイルとは?

JavaScriptのライブラリをTypeScriptなどから利用する場合、TypeScriptは静的型付け言語なので、型の情報が必要になります。そのような場合、JavaScriptのオブジェクトをdeclareを使ったアンビエント宣言することで、型の情報を明示的にすることができます。アンビエント宣言は専用の型定義ファイル( .d.ts )で管理することが推奨されています

独自のカラー「neutral」を使えるように型定義ファイルを作成します

declare module '@mui/material/styles' {
  interface Palette {
    neutral: Palette['primary'];
  }

  interface PaletteOptions {
    neutral?: PaletteOptions['primary'];
  }
}
declare module '@mui/material/Button' {
  interface ButtonPropsColorOverrides {
    neutral: true;
  }
}
export {};

MUIのすべてではないかもしれませんが、PaletteとPaletteOptionsのようにXXXとXXXOptionsというセットの組み合わせになっているのでカスタマイズする場合は両方の変更が必要になります

次にcreateThemeでneutralの色を設定します

  const theme = createTheme({
    palette: {
      neutral: {
        main: '#64748B',
        contrastText: '#fff',
      },
    },
  });

Buttonのprimaryをneutralに変更すると次のように表示されます

Buttonをneutral色に変更

Typography

文字のサイズや装飾などの文字スタイルを変更する場合にはTypographyを使用します

Typographyはさまざまなコンポーネントで継承されているため、Typographyの文字サイズを変更すると他のコンポーネントにも影響します

次はTypographyコンポーネントを使用していないのにCheckboxとButtonのfontsizeが変更された例です

  const theme = createTheme({
    typography: {
      fontSize: 8,
    },
  });
fontSizeを変更

Typographyはデフォルトだとpタグになります

Boxと同様に他のコンポーネントにもなることでき、バリエーションにはh1~h6、MUI独自のsubtitle1など13種類あります

このバリエーションに新しくposterが使えるように型定義ファイルを変更します

declare module '@mui/material/styles' {
  interface TypographyVariants {
    poster: React.CSSProperties;
  }

  interface TypographyVariantsOptions {
    poster?: React.CSSProperties;
  }
}

declare module '@mui/material/Typography' {
  interface TypographyPropsVariantOverrides {
    poster: true;
  }
}
export {};

次にcreateThemeでposterの文字スタイルを設定します

  const theme = createTheme({
    typography: {
      poster: {
        fontSize: '4rem',
        color: 'red',
      },
    },
  });

Typographyコンポーネントのvariantでposterを指定すると次のように表示されます

Typographyのposter

まとめ

今回作成したソースは次の通りです

App.tsx
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import FormControlLabel from '@mui/material/FormControlLabel';
import Typography from '@mui/material/Typography';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import * as React from 'react';
import CustomCheckbox from './components/CustomCheckbox';

function App() {
  const theme = createTheme({
    palette: {
      neutral: {
        main: '#64748B',
        contrastText: '#fff',
      },
    },
    typography: {
      poster: {
        fontSize: '4rem',
        color: 'red',
      },
    },
  });
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <FormControlLabel control={<CustomCheckbox />} label="Label" />
      <Button color="neutral" variant="contained">
        neutral
      </Button>
      <Typography variant="poster">poster</Typography>
    </ThemeProvider>
  );
}

export default App;
CustomCheckbox.tsx
import Checkbox, { CheckboxProps } from '@mui/material/Checkbox';
import { orange } from '@mui/material/colors';
import { styled } from '@mui/material/styles';
import * as React from 'react';

const StyledCheckbox = styled(Checkbox)(({ theme }) => ({
  color: orange[500],
  '&.Mui-checked': {
    color: orange[500],
  },
}));

function CustomCheckbox(props: CheckboxProps) {
  return <StyledCheckbox {...props} />;
}

export default CustomCheckbox;
global.d.ts
declare module '@mui/material/styles' {
  interface Palette {
    neutral: Palette['primary'];
  }

  interface PaletteOptions {
    neutral?: PaletteOptions['primary'];
  }
  interface TypographyVariants {
    poster: React.CSSProperties;
  }

  interface TypographyVariantsOptions {
    poster?: React.CSSProperties;
  }
}
declare module '@mui/material/Button' {
  interface ButtonPropsColorOverrides {
    neutral: true;
  }
}
declare module '@mui/material/Typography' {
  interface TypographyPropsVariantOverrides {
    poster: true;
  }
}
export {};
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次