この記事では、MUI v4 以前の makeStyles()
関数を使ったカスタムスタイル設定方法を説明しています。
MUI v5 以降のカスタムスタイル設定では sx prop
や styled()
関数を使用しますので、下記の記事を参照してください。
Material-UI コンポーネントのスタイル設定
Material-UI が提供する各種コンポーネントには、表示スタイルを切り替えるためのプロパティが用意されています。
例えば、Button コンポーネント は variant
や color
プロパティで見た目を切り替えることができます。
<Button>Default</Button>
<Button variant="contained" color="primary">Primary</Button>
<Button variant="contained" color="secondary">Secondary</Button>
<Button variant="outlined" disabled>Disabled</Button>
多くのケースでは、この仕組みで十分にスタイル設定できるのですが、デフォルトのスタイルから外れた表示をしたり、div
要素など Material-UI 以外のコンポーネントに対して独自の CSS を適用したいことがあります。
このような場合、コンポーネントの実装ファイル内に直接 CSS コードを記述してスタイルをカスタマイズできます(JavaScript 内に記述するので CSS-in-JS と呼びます)。
React の世界では色々な CSS 参照方法がありますが、Material-UI は次のような理由で CSS-in-JS な記述方法を採用しています。
- 現在のテーマ設定に基づいたスタイル設定を行える(例: 基準スペースの2倍のマージンを設定する)
- コンポーネントの
props
の値を使って動的にスタイル設定できる(例:<MyButton color="vivid">
で派手な色のスタイルを設定する)
フックによるスタイル設定 (makeStyle)
Material-UI で、コンポーネントに独自スタイルを設定する方法としては、主に次の 3 種類の方法が用意されています。
- Hook API
makeStyle
関数で生成したフック関数をコンポーネント内で呼び出す方法。一番よく使われてる。
- Styled components API
- 既存のコンポーネント (
Button
など)をラップする形で、スタイルを適用したコンポーネント(MyButton
など)を作成する方法。
- 既存のコンポーネント (
- Higher-order component API
- Styled components に似てるけど、HoC の仕組みでスタイル設定したコンポーネントを作成する方法。ちょっとわかりにくい。
ここでは、一番メジャーで分かりやすい、フックを利用したスタイル設定方法を紹介します。
次の例では、Material-UI の Button
コンポーネントに、独自の CSS スタイル(customButton
クラス)を適用しています。

import { Button } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
const useStyles = makeStyles({
customButton: {
color: 'white',
background: '#229966',
padding: '1em 3em',
},
})
const MyButton: React.FC = () => {
const classes = useStyles()
return <Button className={classes.customButton}>Button</Button>
}
export default MyButton
ポイントは、makeStyles 関数 で作成したフック関数を呼び出して、その戻り値のオブジェクトを使って各コンポーネントの className
プロパティを指定するところです。
基本はこれだけなので、このやり方に慣れてしまえば OK です。
Props によるスタイル設定の分岐
CSS-in-JS なスタイル記述方法の利点の一つとして、次のような動的なスタイル設定があります。
この例では、スタイル設定用のフック関数 (useStyles
) に、StyleProps
型の引数を渡すことでテキストの色を切り替えています。
import { Typography } from '@material-ui/core'
import { makeStyles, Theme } from '@material-ui/core/styles'
// スタイル定義用のフック関数が受け取るプロパティの型
type StyleProps = {
textStyle: 'normal' | 'vivid'
}
const useStyles = makeStyles<Theme, StyleProps>({
customText: {
// 引数で渡されたオブジェクトの値で分岐処理できる
color: (props) => (props.textStyle === 'normal' ? 'black' : '#ff6633'),
},
})
const MyLabel: React.FC = () => {
const classes = useStyles({ textStyle: 'vivid' })
return <Typography className={classes.customText}>Hello</Typography>
}
export default MyLabel
上記の例では、コンポーネントの実装内で StyleProps
オブジェクトを作成して useStyles
に渡していますが、コンポーネント自身の Props
オブジェクトをそのまま渡してしまう方が一般的かもしれません。
import { Typography } from '@material-ui/core'
import { makeStyles, Theme } from '@material-ui/core/styles'
type Props = {
textStyle?: 'normal' | 'vivid'
children: React.ReactNode
}
const useStyles = makeStyles<Theme, Props>({
customText: {
color: (props) => (props.textStyle === 'normal' ? 'black' : '#ff6633'),
},
})
const MyLabel: React.FC<Props> = (props: Props) => {
const classes = useStyles(props)
return (
<Typography className={classes.customText}>{props.children}</Typography>
)
}
MyLabel.defaultProps = {
textStyle: 'normal',
}
export default MyLabel
こうすると、そのコンポーネントを使う側でスタイルを制御できるようになります。

import MyLabel from '../components/MyLabel'
const IndexPage: React.FC = () => {
return (
<div>
<MyLabel>Default Label</MyLabel>
<MyLabel textStyle="normal">Normal Label</MyLabel>
<MyLabel textStyle="vivid">Vivid Label</MyLabel>
</div>
)
}
export default IndexPage
オブジェクト間のマージン用にスタイル設定する
makeStyles
で作成したスタイル設定は、Material-UI のコンポーネント以外にも適用できます。
次の例では、div
要素に独自スタイルを適用し、子要素のマージンを現在のテーマのスペース 1 つ分 (theme.spacing(1)
) に設定しています。
スタイルオブジェクトを入れ子の形で定義すると、プロパティ名の部分で &
を使ってカレント要素を参照できます。

import { Button } from '@material-ui/core'
import { makeStyles, Theme } from '@material-ui/core/styles'
const useStyles = makeStyles((theme: Theme) => ({
root: {
'& > *': {
margin: theme.spacing(1),
},
},
}))
const IndexPage: React.FC = () => {
const classes = useStyles()
return (
<div className={classes.root}>
<Button variant="contained">Button 1</Button>
<Button variant="contained">Button 2</Button>
<Button variant="contained">Button 3</Button>
</div>
)
}
export default IndexPage