👻

Material-UIのwithStylesでカスタマイズ

2021/09/01に公開

はじめに

Material-UI のコンポーネントのスタイルを変更したいなーと思った際に、公式ドキュメントだけでは"withStyles"の利用方法が分かりづらかったので。
色々と使い方はあるみたいだが、とりあえず基本の基本をピックアップ。

withStyles の基本

下記のように withStyles によってコンポーネントを作成し配置する。

const CustomComponent = withStyles({
  root: {
    // ここにスタイルを書いたり
  },
  label: {},
  // etc...
})(カスタムしたいコンポーネント)

// コンポーネントの配置
<CustomComponent />

直接 className や style にスタイルを指定してもよいが、同じレイアウトのものを複数作成したり、変更点が多い場合にスッキリしたコードが書けるのでおすすめ。

root?label?ってなに?

Material-UI の公式ドキュメントの Component API の各ページ下部に CSS という欄がある。
ここの Rule name が withStyles に渡すスタイルの key 名となる。
ButtonのCSS
Button の CSS の一部

実践(Button を例に)

Button にはもともと color プロパティが用意されているがテーマに沿った色しか指定できない。
もっと自由にスタイルを変更してみる。


デフォルト Button

1-1. root にカラー設定

const MyButton = withStyles({
  root: {
    // rootコンポーネントへ適応
    background: '#26a69a', // 背景色
    '&:hover': {
      // hover時背景色
      background: '#1a746b',
    },
    marginRight: 10,
    // color: 'white',  ここに書いてもいいが、せっかくなのでlabelに記述
  },
  label: {
    color: 'white',
  },
})(Button)
...
<MyButton>text</MyButton>   // デフォルトがvariant="text"
<MyButton variant="outlined">outlined</MyButton>
<MyButton variant="contained">contained</MyButton>


root に指定した場合

色は変更できたが、variant それぞれのスタイルが崩れてしまう。
variant ごとの Rule name も用意されているので、そちらに指定することで特定の vairant に対してのみスタイルを当てることができる。

1-2. variant ごとに設定

const MyButton = withStyles({
  root: {
    marginRight: 10,
  },
  // variant="text"のみ適応
  text: {
    color: '#03a9f4',
  },
  // variant="outlined"のみ適応
  outlined: {
    border: '1px solid #e65100',
    '&:hover': {
      background: '#ffe0b2',
    },
  },
  // variant="contained"のみ適応
  contained: {
    color: 'white',
    background: '#43a047',
    '&:hover': {
      background: '#2e7031',
    },
  },
})(Button)
...
<MyButton>text</MyButton>   // デフォルトがvariant="text"
<MyButton variant="outlined">outlined</MyButton>
<MyButton variant="contained">contained</MyButton>


各 variant に個別設定した場合

1-3. ちょっと特殊なものの紹介

1-3-1. 概要

上記とは少し異なった実装をしなければならないパターンも紹介します。
自分は最初わからず躓きました...
たとえば、Button にはこんなルールがあります。

今までのパターンでいけば disabled が設定された際に適応されるなと想像できます。
実際に指定して disabled 時の文字色を赤にしてみます。

const MyButton = withStyles({
  root: {
    // 見栄えのためにつけているだけです
    marginRight: 10,
  },
  disabled: {
    color: 'rgba(255, 0, 0, 0.26)',
  },
})(Button)

<MyButton variant="contained">disabled</MyButton>
<MyButton variant="contained" disabled>
    disabled
</MyButton>

...変化なし!
一度 Chrome の開発者ツールを覗いてみると

自動で付与される style に優先順位で負けてます。
本来であれば設定したものが上に来てほしいのですが。

1-3-2. 解決策

ドキュメントを漁ると Global class が Mui-から始まるもの、または、Description に 「Pseudo-class applied ~」と記載のあるものは root に$ruleName で指定する必要があるようです。(Pseudo-class は擬似クラスで desabled や checked, selected のようなものが該当)

const MyButton = withStyles({
  root: {
    // 見栄えのためにつけているだけです
    marginRight: 10,
    // &$ruleNameで指定
    '&$disabled': {
      color: 'rgba(255, 0, 0, 0.26)'
    }
  },
  disabled: {
    // 必ず空を用意
  },
})(Button)

<MyButton variant="contained">disabled</MyButton>
<MyButton variant="contained" disabled>
    disabled
</MyButton>


disable 時の文字色を赤に

1-4. その他

上記で紹介したもの以外でも outlinedPrimary(variant="outlined", color="primary")や textSizeLarge(variant="text", size="large")など更に細かな設定条件のルールもある。
下記を参考にしていろいろ試してみてください。
Button の CSS

おわりに

withStyles によるコンポーネントのカスタマイズ方法を紹介しました。
Component API の CSS 欄を確認し、Rule name を key に実装するという方法でした。
また、疑似クラスの disabled, selected 等は注意が必要であることは覚えておいてください。
今回は Button を例に紹介しましたが、Select, List 等のコンポーネントでも同じようにカスタマイズができます。
(例えば、ListItem が selected 時の背景色を変えたい等)
ぜひ様々なコンポーネントを使って試してみてください!

Discussion