🍣

MUI styled() vs @emotion/react vs @emotion/styled どれを使えばいいか

2023/07/23に公開

自分の結論

Themeが最も簡単に反映されて、propsを指定することで動的にstyleを変更することができるMUIのstyled()を基本に使って、複数のstyleを当てたい時は@emotion/reactを使う。
@emotion/styledがある理由はよく分からない🤔
(でもこれらを使うときはstyleを当てる要素が一種のcomponentみたいに(意味的に)切り出せるときで、基本はsx props使うけど。)

はじめに

なんか、Material UI使うときって

yarn add @mui/material @emotion/react @emotion/styled

でインストールしろってドキュメントに書かれてますが、@mui/materialと@emotion/reactと@emotion/styledそれぞれでstyleの指定の仕方があって、どれがいいんだろう(そしていらないやつは消したい)と思ってそれぞれの使い方を調べてみました。

詳細

MUI styled()

使い方

import { Box, styled } from '@mui/material'

const StyledBox = styled(Box)<{ white?: boolean }>(({ theme, white }) => ({
  width: 200,
  height: 50,
  background: theme.palette.background.default,
  color: white ? "white" : undefined,
}))

export const Component: React.FC = () => {
  return (
    <>
      <StyledBox>StyledBoxです</StyledBox>
      <StyledBox white>文字色が白のStyledBoxです</StyledBox>
    </>
  )
}

メリット

  • ThemeProviderで設定したthemeが使える。
  • propsを使って動的にstyleを変更可能。

デメリット

  • なんのタグを使っているかわかりにくいという話がある?(MUIではなくHTMLタグにstyleを当てる場合などで、SEO的に使っているタグが把握しやすいようにしたい場合とかだろうか?)
  • styleは同じままタグを変えたい場合はもう一個作るしかない。
  • 作った複数のstyleを一つのコンポーネントに当てることはできない。

その他

  • テンプレートリテラル方式有。IDEの補完機能は拡張機能が多分ある。

@emotion/react

使い方

※使う前にcss propを有効化するいくつかの設定が必要だが、その紹介はここでは省略する(例えばこれを参考にする)。

import { css } from '@emotion/react'
import { Box } from '@mui/material'

export const Component: React.FC = () => {
  return (
    <>
      <Box
        css={(theme) =>
          css({
            width: 200,
            height: 50,
            background: theme.palette.background.default,
          })
        }
      >
        themeを使う例です
      </Box>
      <Box css={[style1, style2]}>複数のstyleを指定する例です</Box>
    </>
  )
}

const style1 = css({
  width: 200,
  height: 50,
})

const style2 = css({
  color: 'white',
})

// これはtheme設定のファイルとかで宣言しておく
declare module '@emotion/react' {
  interface Theme {
    palette: { background: { default: string } }
  }
}

メリット

  • styleは同じままタグを変えるのは余裕。
  • なんのタグを使っているかわかりやすい。
  • 複数のstyleを当てることができる。

デメリット

  • TypeScriptでthemeを当てる際は、themeの型を定義しないといけない(例の一番下のdeclare文)。
  • propsに応じた動的なスタイルの変更はできない。
  • css propを使うために設定しないといけないのがちょっと面倒くさい。

その他

  • @emotion/reactにもThemeProviderがあるが、それを使わずとも@mui/materialのThemeProviderを使っていれば、自動的に@emotion/reactの方にもthemeが反映されるようである。
  • テンプレートリテラル方式有。IDEの補完機能用に多分拡張機能がある。
  • css()のimport先は@mui/materialからもできるようだ。

@emotion/styled

使い方

import { styled } from '@emotion/styled'

// 後の使い方はMUI styled()と同じ。

メリット

  • MUI styled()と同じ。

デメリット

  • MUI styled()と同じ。
  • TypeScriptでthemeを当てる際は、themeの型を定義しないといけない(例の一番下のdeclare文)。

その他

  • @emotion/reactにもThemeProviderがあるが、それを使わずとも@mui/materialのThemeProviderを使っていれば、自動的に@emotion/reactの方にもthemeが反映されるようである。
  • テンプレートリテラル方式有。IDEの補完機能用に多分拡張機能がある。

終わりに

なんか色々調べて、@mui/materialのパッケージだけあればいいのではと思った。
だって、css()も、結局@emotion/reactじゃなくて、@mui/materialからimportできるみたいだし(でもそういえばcss propを使うための設定で@emotion/reactは必要だった)、styled()も、@emotion/styledよりMUIのstyled()の方がthemeが型定義無しにできる点で上位互換だから。でも、だったらなんで公式は3つもインストールさせるんだろう…。

Discussion