😸

Material-UI v4でコンポーネントのデザインをカスタムする方法

2022/11/21に公開

グローバルのCSS設定をカスタムする

コンテキストを作ってその中でCSSのデフォルト設定をカスタムする
Iconの大きさや、Typographyのフォント設定などをグローバルにカスタムできる。
VScodeを使っていれば、control + spaceで、設定項目を教えてもらえる。

カスタムCSSを設定

theme.ts
import { createMuiTheme, ThemeOptions } from '@material-ui/core/styles';

const DROPDOWN_BOX_SHADOW =
  '0px 2px 8px rgba(0, 0, 0, 0.12), 2px 0px 8px rgba(0, 0, 0, 0.12)';

export const theme = (options: ThemeOptions = {}) => {
  return createMuiTheme({
    overrides: {
      // SvgIconサイズをカスタム
      MuiSvgIcon: {
        fontSizeSmall: {
          '& > *:first-child': {
            fontSize: 10
          }
        },
        fontSizeLarge: {
          fontSize: ICON_SIZES.regular,
          '& > *:first-child': {
            fontSize: 20
          }
        }
      },
      // Iconサイズをカスタム
      MuiIcon: {
        fontSizeSmall: {
          '& > *:first-child': {
            fontSize: 10
          }
        },
        fontSizeLarge: {
          fontSize: ICON_SIZES.regular,
          '& > *:first-child': {
            fontSize: 20
          }
        }
      },
      // Buttonサイズをカスタム
      MuiButton: {
        iconSizeSmall: {
          '& > *:first-child': {
            fontSize: 10
          }
        },
        iconSizeMedium: {
          '& > *:first-child': {
            fontSize: 20
          }
        },
        iconSizeLarge: {
          '& > *:first-child': {
            fontSize: 25
          }
        }
      }
    },
    // Typographyをカスタム
    typography: {
      fontFamily: "'Noto Sans JP', sans-serif;",
      h1: {
        fontSize: 24,
        fontWeight: 700
      },
      h2: {
        fontSize: 24,
        fontWeight: 700
      },
     ...
    },
    // パレットを設定
    palette: {
      primary: {
        main: 'green'
      },
      secondary: {
        main: 'blue'
      },
      text: {
        primary: COLORS.textBlack,
        secondary: COLORS.textGray
      }
    },
    // その他
    shape: {
      borderRadius: 4
    },
    zIndex: {
      appBar: 1250 
    },
    shadows: [
      'none',
      DROPDOWN_BOX_SHADOW,
      ...Array(23).fill('none')
    ] as Shadows,
    ...options
  });
};

コンテキスト内でカスタムCSSを適用

コンテキストはグローバルに設定することもできるし、ローカルに設定することもできる。
下記はNext.jsでグローバルに設定する場合。

_app.tsx
import { MuiThemeProvider } from '@material-ui/core/styles';
import { theme } from './theme';
...

return (
    <MuiThemeProvider theme={theme()}>
      <Your-Components-Here>
    </MuiThemeProvider>
  );
}

参考

https://v4.mui.com/customization/theming/

スクロールバーのCSSをグローバル設定する

スクロールバーのグローバル設定は特殊だったのでメモ。MuiCssBaselineを設定する必要がある。

customScrollbar.tsx
import CssBaseline from '@material-ui/core/CssBaseline';
import { MuiThemeProvider } from '@material-ui/core/styles';

const theme = createTheme({
  overrides: {
    MuiCssBaseline: {
    '@global': {
          '*::-webkit-scrollbar': {
            width: 8
          },
          '*::-webkit-scrollbar-track': {
            borderRadius: 4,
            background: '#BDBDBD'
          },
          '*::-webkit-scrollbar-thumb': {
            borderRadius: 4,
            background: '#BDBDBD'
          }
        }
    },
  },
});

...
return (
  <MuiThemeProvider  theme={theme}>
    <CssBaseline /> 
    <Your-Component-Here>
  </MuiThemeProvider >
);

参考

https://v4.mui.com/customization/globals/#global-css

コンポーネントのCSSカスタマイズ

ClassNameを使ってカスタマイズできる。
Propsによるスタイル設定の分岐も可能。

下記はCustom Inputを使った例。

デフォルト

Focusがあたったとき

textInput.tsx
import React from 'react';
import InputBase from '@material-ui/core/InputBase';
import FormControl from '@material-ui/core/FormControl';
import FormLabel from '@material-ui/core/FormLabel';
import { makeStyles, Theme } from '@material-ui/core/styles';

export type Props = {
  widthInPercent?: number;
  label: string;
  text: string;
  placeholder?: string;
  onTextChange: (text: string) => void;
};

const useTextFormStyles = makeStyles<Theme, { widthInPercent?: number }>({
  formControl: {
    width: ({ widthInPercent }) =>
      widthInPercent ? `${widthInPercent}%` : 'auto',
    maxWidth: '100%'
  },
  label: {
    color: '#757575',
    fontSize: 12,
    fontWeight: 400,
    '&.Mui-focused': {
      color: '#BDBDBD'
    }
  },
  text: {
    backgroundColor: '#FFFFFF',
    borderRadius: 4,
    border: `#BDBDBD solid 1px`,
    fontSize: 14,
    fontWeight: 400,
    '&.Mui-focused': {
      border: `#1F79CC solid 1px`,
      color: '#323030'
    },
    '& .MuiInputBase-input': {
      height: 32,
      padding: `0px 8px`
    },
    marginTop: 0
  }
});

export const TextForm: React.FC<Props> = ({
  widthInPercent,
  label,
  text,
  placeholder,
  onTextChange
}) => {
  const classes = useTextFormStyles({ widthInPercent });

  return (
    <FormControl className={classes.formControl}>
      <FormLabel className={classes.label}> {label}</FormLabel>
      <InputBase
        className={classes.text}
        value={text}
        onChange={(e) => onTextChange(e.target.value)}
        placeholder={placeholder}
      />
    </FormControl>
  );
};

Focusがあたった部分のCSSをカスタマイズするには?

FocusがあたったときのCSSをカスタマイズするためには、該当するCSSクラス名を指定して記述すればよい。

    '&.Mui-focused': {
      border: `#1F79CC solid 1px`,
      color: '#323030'
    },

ではどうやってクラス名を特定するのか

Focusが当たった部分のクラス名はドキュメントに書いてある。

ドキュメントを見なくてもDev toolで分かる

また、ブラウザのDev toolのElementsタブで該当するエレメントをinspectすれば分かる。
ドキュメントに書いていない細かい部分のCSSをカスタマイズしたいとき、細かい部分のクラス名を調べるためにはDev toolでinspectする必要がある。

Classes属性をつかう場合

前述のやりかたではMUIコンポーネントのclassName属性をつかったが、classes属性を使ってカスタムCSSを指定することもできる。

const useTextFormStyles = makeStyles<Theme, { widthInPercent?: number }>({
  ...
  text: {
    backgroundColor: #FFFFFF,
    borderRadius: BORDER_RADIUSES.regular,
    border: `#BDBDBD solid 1px`,
    fontSize: 14,
    fontWeight: 400,
-    '&.Mui-focused': {
-      border: `#1F79CC solid 1px`,
-      color: '#323030'
-    },
    '& .MuiInputBase-input': {
      height: 32,
      padding: `0px 4px`
    },
    marginTop: 4
  },
+  textFocus: {
+    border: `#1F79CC solid 1px`,
+    color: #323030
+  }
});

export const TextForm: React.FC<Props> = ({
  widthInPercent,
  label,
  text,
  placeholder,
  onTextChange
}) => {
  const classes = useTextFormStyles({ widthInPercent });

  return (
    <FormControl className={classes.formControl}>
      <FormLabel className={classes.label}> {label}</FormLabel>
      <InputBase
         className={classes.text}
+       classes={{ focused: classes.textFocus }}
        value={text}
        onChange={(e) => onTextChange(e.target.value)}
        placeholder={placeholder}
      />
    </FormControl>
  );
};

classes属性に指定できるkeyはどうやって分かるの?

control + shiftでVScodeが教えてくれるが、ドキュメントにも書いてある。

Discussion