【MUI (Material UI)】 それ、中に Typography を書かなくてもいいですよ ―― 継承とコンポジションを添えて

# はじめに

:::note 
この記事は、@mui/material の v5 が対象です。
:::

Material UI (@mui/material)   には、 **Typography** というコンポーネントがあり、これを使うことでデザインシステムで定義された文字スタイルを当てることができます。

ところで、Material UI のさまざまなコンポーネントに、 Typography コンポーネントを中に明示的に書かなくても同じ方法でスタイルを当てる機能があることをご存知ですか？


Material UI のコンポーネントは、**継承・コンポジション**によって、他のコンポーネントの機能を利用する実装になっているモノが多くあります。

そのようなコンポーネントを使うときには、中に Typography を追加で書く必要がありません。

```tsx:こういう使い方はしなくていい！
<Link>
  <Typography variant="subtitle">
    リンク文字列文字列文字列
  </Typography>
</Link>
```

---

このように `Typography` をわざわざ追加で書かなくても良いコンポーネントについて、

- [A. 継承](#a-継承)
- [B. コンポジション](#b-コンポジション)

の2グループに分けて解説していきます。

# A. 継承

[MUI の API設計アプローチ / spread の章](https://mui.com/material-ui/guides/api/#spread) で、 `<MenuItem disableRipple` と指定したとき、その `disableRipple` prop が `MenuItem > ListItem > ButtonBase` と渡されていく例が示されています。

[Link コンポーネントの API / Props の章](https://mui.com/material-ui/api/link/#props) のはじめを見てみると、

> Props of the Typography component are also available.

と書かれています。このコンポーネントは、いわば Typography を「継承」したコンポーネントのように振る舞うものであり、 `color`, `variant` などの prop は、 `Link > Typography` と渡されていきます。

```tsx
{/* color, variant が Typography の Prop として指定される */}
<Link color="error" variant="subtitle1">
  サブタイトルのサイズでエラー色のリンク
</Link>
```

## 例

:::note
"Props of the Typography component are also available." で検索した結果です。
:::

### `Link`

https://mui.com/material-ui/api/link/

### `DialogContentText`

https://mui.com/material-ui/api/dialog-content-text/

### `TimelineContent`

https://mui.com/material-ui/api/timeline-content/

### `TimelineOppositeContent`

https://mui.com/material-ui/api/timeline-opposite-content/



# B. コンポジション

https://ja.reactjs.org/docs/composition-vs-inheritance.html

上記の例に出てくる **コンポジション** パターンに関連するコンポーネントも複数あります。

`ListItemText` の例を見てみましょう。

```tsx
<ListItemText
  primary="最重要テキストテキスト"
  primaryTypographyProps={{ color: "primary" }}
  secondary="二次的テキストテキストテキスト"
  secondaryTypographyProps={{ color: "error" }}
/>
```

この例では `primary`, `secondary` という2つのPropが、 `ListItemText` のコンテンツに反映されるProps (この記事では仮に **スロット Props** と呼びます) として存在しています。

以下の例に当たる Material UI のコンポーネントにおいては、このような **スロット** に裸の string を渡した場合に

```tsx
<Typography>{props.primary}</Typography>
```

といった具合に、その string が Typography に包まれます。

`primaryTypographyProps` といった、 (スロット名)TypographyProps の形の Prop に、その Typography に渡されてほしい Props オブジェクトを受け取ることもあります。

また「勝手に Typography で包まないでよ💢」と困る場合もあると思います。そのような時のために、`disableTypography` という Prop が生えているケースがあります。

## 例

### `ListItemText`

https://mui.com/material-ui/api/list-item-text/

`ListItemText` は、複合コンポーネント `ListItem` の構成要素の一つで、文字コンテンツに使用するコンポーネントです。

該当するスロット Props と、それに対応するカスタマイズ用 Props

- **`primary`**
  - `primaryTypographyProps`
- **`secondary`**
  -  `secondaryTypographyProps`

### CardHeader

https://mui.com/material-ui/api/card-header/

`CardHeader` は、複合コンポーネント `Card` の構成要素の一つで、ヘッダー部分（アバターもふくむ） になります。

https://mui.com/material-ui/react-card/

該当するスロット Props と、 それに対応するカスタマイズ用 Props

- **`title`**
  - `titleTypographyProps`
- **`subheader`**
  - `subheaderTypographyProps`

### InputAdornment

https://mui.com/material-ui/api/input-adornment/

`InputAdornment` は、 入力フィールドを構成する `○○○Input` 系要素の先頭・末尾に入れる装飾のためのコンポーネントです。

https://mui.com/material-ui/react-text-field/#input-adornments

該当するスロット Props 

- **`children`** 
  - 対応するカスタマイズ用 Prop は無し

### FormControlLabel

https://mui.com/material-ui/api/form-control-label/

該当するスロット Prop と、 それに対応するカスタマイズ用 Prop

- **`label`**
  - `componentsProps: { typography: {...} }`