MUIのTypography — 文字の見た目と意味を分けて指定する
この章の目次開く
MUIで文字を書くとき、素の <p> や <h2> を置いてもかまいません。ただし Typography を使うと、テーマで決めたフォントサイズや行間が自動で当たります。
このコンポーネントには、他のUIライブラリにあまりない考え方が入っています。「どう見えるか」と「HTMLとして何であるか」を別々のpropで指定するという設計です。
学習者variant="h4" って書いたら <h4> タグになるんじゃないの?わざわざ2つに分ける意味がわからない…。
既定ではそのとおり <h4> になります。分けられるのは、見た目の大きさと見出しレベルが一致しない場面があるからです。
variantとcomponentの役割
<Typography variant="h4" component="h2">
セクション見出し
</Typography>| prop | 役割 |
|---|---|
variant | 見た目のプリセット(フォントサイズ・太さ・行間) |
component | 実際に描画されるHTMLタグ |
上の例は「文字の大きさは h4 相当、HTMLとしては <h2>」という指定です。
なぜこれが要るのか。ページ内の2つ目の大見出しは、HTMLの構造上は <h2> であるべきですが、デザイン上は小さめにしたいことがあります。<h4> タグで書いてしまうと、見出しレベルが h1 → h4 と飛び、スクリーンリーダーでの拾い読みがしづらくなります。
見た目のためにタグを選ばない。これがこのpropが存在する理由です。

variantごとに描画されるタグ
component を省略したときに何になるかは、決まった対応表があります。
| variant | 描画されるタグ |
|---|---|
h1 〜 h6 | 同じ名前のタグ(<h1> 〜 <h6>) |
subtitle1 / subtitle2 | <h6> |
body1 / body2 | <p> |
button / caption / overline | <span> |
どのタグになるかの決定順
実装では、次の順で最初に見つかったものが使われます。
componentprop(指定があれば最優先)variantMappingprop(そのコンポーネントだけの対応表)- 既定の対応表(上の表)
- どれにも当てはまらなければ
<span>
button / caption / overline が <span> になるのは、既定の対応表に載っておらず4番目に落ちるためです。
余白は自分で付ける
Typography の既定スタイルには margin: 0 が入っています。ブラウザが <h1> や <p> に付ける余白は消えます。
<Typography variant="h4">見出し</Typography>
<Typography variant="body1">本文がすぐ下に詰まる</Typography>意図的な設計です。余白はレイアウト側で決めるという考え方で、Stack の spacing や sx の mb で付けます。
手軽に下余白だけ足したい場合は gutterBottom が使えます。
<Typography variant="h4" gutterBottom>見出し</Typography>これで margin-bottom: 0.35em が付きます。文字サイズに比例する相対値なので、見出しが大きいほど余白も広がります。厳密に揃えたいときは sx={{ mb: 2 }} のほうが確実です。
noWrap — はみ出しを省略記号にする
テーブルのセルやカードのタイトルで、長い文字列が折り返して高さを壊すことがあります。
<Typography noWrap>とても長いタイトルがここに入ります</Typography>これ1つで、次の3つのCSSがまとめて当たります。
| プロパティ | 値 |
|---|---|
overflow | hidden |
text-overflow | ellipsis |
white-space | nowrap |
結果として、はみ出した部分が … で省略されます。
先生noWrap が効かない相談のほとんどは、MUIではなくCSSの話です。省略記号は「幅が決まっていること」が前提だと覚えておいてください。
colorとalign
色はテーマのパスを文字列で渡せます。
<Typography color="text.secondary">補足のテキスト</Typography>
<Typography color="error">エラーメッセージ</Typography>text.primary / text.secondary のようなパスのほか、primary や error といった役割の名前も受け取ります。生の色コードを書かずテーマ経由にしておくと、ダークモードで自動的に切り替わります。
揃え方は align です。
<Typography align="center">中央寄せ</Typography>'inherit'(既定)/ 'left' / 'center' / 'right' / 'justify' から選びます。
プロジェクト全体で対応表を変える
「このアプリでは subtitle1 を常に <p> にしたい」という方針があるなら、テーマにまとめられます。
createTheme({
components: {
MuiTypography: {
defaultProps: {
variantMapping: {
subtitle1: 'p',
subtitle2: 'p',
},
},
},
},
});毎回 component="p" と書く必要がなくなります。カスタマイズの段階としては、カスタマイズの4段階で扱った「全体の方針はテーマに書く」に当たります。
v9で削除されたprop
古い記事には次の書き方が出てきます。
// v8以前。v9では動かない
<Typography paragraph>段落テキスト</Typography>paragraph は <p> で描画しつつ下余白を付けるpropでしたが、v9の型定義には存在しません。body1 が既定で <p> になるため、役割が重複していたものと考えられます。
現在はこう書きます。
<Typography variant="body1" gutterBottom>段落テキスト</Typography>また3章で触れたとおり、Typography からは system propsも削除されています。<Typography mt={2}> は動かないので、sx に移してください。
よくあるハマりどころ
見出しの下に余白がない
margin: 0 が既定です。gutterBottom か sx で付けます。
subtitle を並べたら見出し構造が壊れた
subtitle1 / subtitle2 は <h6> で描画されます。補足なら component="p" を指定します。
noWrap が効かない
親要素の幅が決まっていません。Flexboxの子なら sx={{ minWidth: 0 }} も併せて確認します。
<Typography mt={2}> が無視される
v9でsystem propsが削除されました。sx={{ mt: 2 }} に書き換えます。
文字サイズをテーマで変えたのに一部だけ変わらない
variant を指定していない Typography は body1 相当になります。変更したのが h1 の設定だけなら、本文には反映されません。
ちゃんと使うためのポイント
-
variantは見た目、componentはHTMLタグ。見た目のためにタグを選ばない subtitle1/subtitle2は既定で<h6>。補足に使うならcomponent="p"button/caption/overlineは<span>- 既定は
margin: 0。余白はgutterBottomかsxで付ける noWrapは幅が決まっていて初めて効く- 色はテーマのパスで指定するとダークモードに追従する
- v9では
paragraphprop とsystem propsが削除された
次の章では、色やフォントをまとめて管理するテーマの構造を扱います。