🌀

Vite+React+TypeScript で、UIフレームワークにMUI(v5)を導入する。

2022/03/06に公開

今回は、UIフレームワークをどれにしようか調べました。

UIフレームワークにもとめる要件は

  • データを表示するためにグリッドの機能が豊富であること。
  • 見た目のカスタマイズが容易であること。
  • 遅くならないこと。

この3点を満たしていたのが、MUI(旧Material-UI)です。

偶然にも、以前にCSSスタイルとして導入を決めたEmotionと相性がとても良いので、
今回はあまり悩まずに MUI(v5) に決定しました。

過去記事:
Vite+React+TypeScriptで、CSSスタイルについて調べて、Emotionに流れ着いた

MUI(v5)

https://mui.com/
MUI は、もともと Material-UI という UIフレームワークで、2021/09/16に MUI としてメジャーアップデートした、Material Design ベースのUIコンポーネントライブラリです。
基本機能は無料ですが DataGridの一部機能や、DateRangePicker を使用するには Pro版(早期割引価格 $186 )が必要です。(価格プラン

npm trends で確認してみました。
React BootstrapAnt Design と比較して、MUI もダウンロード数が多いです。

MUI の導入

Vite で作成した React(TypeScript)に MUI を導入します。create-react-app で作成したアプリとは導入方法が異なるようです。
MUI のデフォルトのスタイリングエンジンは Emotion です。
他に styled-components をスタイリングエンジンに使用することもできます。

今回はスタイリングエンジンに Emotion を使う方法で導入していきます。

インストール

MUI のスタイリングエンジンとして、Emotion を使用する場合のインストールです。
また MUI でアイコンを使用するのに必要な「@mui/icons-material」もインストールしておきます。

npm install @mui/material 
npm install @emotion/react 
npm install @emotion/styled
npm install @mui/icons-material

設定

各tsxファイルにプラグマ [import React from 'react'] の記述がないと、ランタイムエラー「React is not defined」になるため、tsconfig.json に下記を記述します。
また、この記述をすると後述の Emotion の機能を使用したスタイル設定でプラグマ [import jsx from '@emotion/react'] も省略できます。

tsconfig.json(抜粋)
"compilerOptions": {
    ・・・中略・・・
    "jsxImportSource": "@emotion/react",

vite.config.tsは、tsconfig.json の jsxImportSource を参照しないので、こちらにも追記します。

vite.config.ts
vite.config.ts(抜粋)
  plugins: [react({
    jsxImportSource: '@emotion/react',
  })]

Roboto Font

MUI は Roboto フォントを意識して設計されているので、Roboto フォントを使用できるようにします。
また デフォルトのタイポグラフィーの設定では、300、400、500、700のフォントウェイトが使用されています。
Google Web Fonts を使用してRobotoフォントを使用できるように、index.ts に 下記を追加します。

index.ts
<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
/>

Font icons

MUI の Icons コンポーネントを使用するためには、マテリアルアイコンフォントを使用できるようにします。
Google Web Fonts を使用してマテリアルアイコンフォントを使用できるように、index.ts に 下記を追加します。

index.ts
<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>

リセットCSS

ブラウザにはデフォルトCSSとよばれるあらかじめ適用されたスタイルがあります。このデフォルトスタイルはブラウザごとにバグや微妙な差があり、この差を調整してくれるのがリセットCSSです。
詳しくはコチラを参照:Vite+React+Emotionに、リセットCSSを導入する。

MUI が用意しているリセットCSSを App.tsx などのルートコンポーネントに配置しておきます。

App.tsx
import CssBaseline from '@mui/material/CssBaseline'

export function App() {
  return (
    <CssBaseline />
  )
}

この MUI が用意しているリセットCSSは、MUI のコンポーネントでだけ有効で、自前で使用するタグ要素には効果がありません。

動作確認

動作確認としてアイコン付きボタンを表示してみます。
アイコンはコチラから選びます。:https://fonts.google.com/icons

App.tsx
import CssBaseline from '@mui/material/CssBaseline'
import Button from '@mui/material/Button'
import ThumbUp from '@mui/icons-material/ThumbUp'

export function App() {
  return (
    <>
      <CssBaseline />

      <Button variant="outlined" startIcon={<ThumbUp />}>
        OK
      </Button>

    </>
  )
}

MUI コンポーネントへのスタイルの当て方

MUI コンポーネントにスタイルを当てる方法はいろいろあります。

sx プロップに直接指定する

MUI の Buttonコンポーネントの sx プロップに直接スタイルを指定する方法です。

App.tsx
import CssBaseline from '@mui/material/CssBaseline'
import Button from '@mui/material/Button'

export function App() {
  return (
    <>
      <CssBaseline />
      <Button variant="contained" sx={{ backgroundColor: '#db8e98', color: '#46653b'}}>
        MUI Button
      </Button>
    </>
  )
}

sx プロップに事前定義したスタイルを指定する

事前に定義しておいたスタイルを、sx プロップに指定することもできます。

Sample.tsx
import CssBaseline from '@mui/material/CssBaseline'
import Button from '@mui/material/Button'

const style = {
  button1: {
    backgroundColor: '#db8e98',
    color: '#46653b'
  },
  button2: {
    backgroundColor: '#255a60',
    color: '#ccd47e'
  }
}

export function App() {
  return (
    <>
      <CssBaseline />
      <Button variant="contained" sx={style.button1}>
        MUI Button 1
      </Button>
      <Button variant="contained" sx={style.button2}>
        MUI Button 2
      </Button>
    </>
  )
}

スタイル付きコンポーネントを作成する

スタイルを当てたコンポーネントを作成する方法です。

App.tsx
import CssBaseline from '@mui/material/CssBaseline'
import { styled } from '@mui/material'
import Button from '@mui/material/Button'

const CustomButton = styled(Button)({
  backgroundColor: '#db8e98',
  color: '#46653b'
})

export function App() {
  return (
    <>
      <CssBaseline />
      <CustomButton variant="contained">MUI Custom Button</CustomButton>
    </>
  )
}

Emotion の cssプロップに Inline Style で指定する

Emotion の スタイル指定(String Style 又は Object Style)を使用して、css プロップに直接スタイルを指定する方法です。

App.tsx
import CssBaseline from '@mui/material/CssBaseline'
import Button from '@mui/material/Button'
import { css } from '@emotion/react'

export function App() {
  return (
    <>
      <CssBaseline />

      {/* String Style */}
      <Button variant="contained" css={css`background-color: #db8e98; color: #46653b`}>
        MUI Button
      </Button>

      {/* Object Style */}
      <Button variant="contained" css={{ backgroundColor: '#db8e98', color: '#46653b'}}>
        MUI Button
      </Button>
    </>
  )
}

Emotion の cssプロップに事前定義したスタイルを指定する

Emotion の スタイル指定(String Style 又は Object Style)を使用して、css プロップに事前定義したスタイルを指定する方法です。

App.tsx
import CssBaseline from '@mui/material/CssBaseline'
import Button from '@mui/material/Button'
import { css } from '@emotion/react'

const stringstyle = {
  button1: css`
    background-color: #db8e98;
    color: #46653b;
  `,
  button2: css`
    background-color: #255a60;
    color: #ccd47e;
  `
}

const objectstyle = {
  button1: 
  {
    backgroundColor: '#db8e98',
    color: '#46653b'
  },
  button2: 
  {
    backgroundColor: '#255a60',
    color: '#ccd47e'
  }
}


export function App() {
  return (
    <>
      <CssBaseline />

      {/* String Style */}
      <Button variant="contained" css={stringstyle.button1}>
        MUI Button 1
      </Button>
      <Button variant="contained" css={stringstyle.button2}>
        MUI Button 2
      </Button>

      {/* Object Style */}
      <Button variant="contained" css={objectstyle.button1}>
        MUI Button 1
      </Button>
      <Button variant="contained" css={objectstyle.button2}>
        MUI Button 2
      </Button>
    </>
  )
}

まとめ

MUI は初めての使用ですが、公式サイトも充実していますし日本語サイトも豊富なので、あまり迷わず導入できました。

Discussion