32
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MUI (Material UI) の TextField のスタイルを整える ―― 例のチョコチョコ動くラベルを止める

Last updated at Posted at 2022-09-16

Material UI を使った開発で困ることと言えば、TextField の見た目ですよね?

Material UI 公式サイトの TextField のスクリーンショット  
(Material UI 公式サイト のスクリーンショット)

Material Design のガイドラインには準拠しているようですが、左上に縮こまったラベルはサイズが小さすぎて、日本語環境においては不便極まりなく、一般的にもあまりウケがよくないデザインだと思います。

動かない、読めるサイズのラベル・普通の枠線付きの入力エリア、これらが普通に縦に並んでいる入力フィールドが欲しいですよね?

Material UI のテーマ機能を使えば、TextField の各パーツの見た目をカスタマイズして、ラベルが動かない普通の見た目にできます。

これで MUI Base や Joy UI をプロジェクトに導入するまでの間をしのぎましょう。

実は、現在 Alpha 版の MUI Base (@mui/base) を使えば、スタイル抜きの入力フォームを使って見た目を自由自在にカスタマイズすることが出来ます。

また、現在開発が進められている Material UI の姉妹ライブラリである Joy UI (@mui/joy) には、ズバリ、マトモな見た目の TextField が含まれています。

Joy UI の TextField のデモンストレーションのスクリーンショット
(Joy UI 公式 のスクリーンショット)

使用ライブラリとバージョン

ライブラリ バージョン
@mui/material 5.10.2
@emotion/react 11.10.0
@emotion/styled 11.10.0

カスタマイズの方法

今回は MUI のテーマ機能を使って、TextField のスタイルを直接上書きしてしまいます。

▼ この記事の3番の方法になります。

他にも、TextField をラップしたコンポーネントを自作してそちらを使う方法もありますが、forwardRef, className, sx, controlled/uncontrolled の管理などを怠ると、各利用箇所(例:横幅を調整する、refから操作する)で問題が出て、対処が後手に回ることになると思うので、この方法を取りました。

(あと、フォーカスすると青くなったり、エラーだと赤くなったりする挙動は継承したい、要はラクしたいというのもあります。)

(同じ理由で、'@mui/material/styles' から利用可能な styled() も良い選択肢だと思います。)

まずは結論から

まともなスタイルが当てられたフィールド

まずは、

<TextField
  name="taskName"
  label="タスク名"
  sx={{ display: "flex", maxWidth: 360 }}
  helperText="ああああ"
  margin="normal"
/>

と記述したときに、上図のようなスタイルが得られるテーマの記述を挙げて、その後ろに解説を続けます。

デフォルトで display: inline-flex で、そこは上書きしていないので、フィールドを縦に並べたい場合には flex に変えましょう。


createTheme は、同名の関数が他のパッケージにもあるので、 "@mui/material" からインポートするように要注意!!

import { createTheme } from "@mui/material";

const theme = createTheme({
  components: {
    // TextField 関連のコンポーネントのスタイルを調整する
    MuiInputLabel: {
      styleOverrides: {
        formControl: {
          // 移動をクリック時に動かないように固定
          position: "static",
          transform: "none",
          transition: "none",
          // クリックを可能に
          pointerEvents: "auto",
          cursor: "pointer",
          // 幅いっぱいを解除
          display: "inline",
          alignSelf: "start",
          // タイポグラフィを指定
          fontWeight: "bold",
          fontSize: "0.75rem",
          // テーマの Composition を使えば以下のようにも書ける
          // base.typography.subtitle2
        },
      },
    },
    MuiOutlinedInput: {
      styleOverrides: {
        root: {
          // デフォルトだと、
          // ラベルをはみ出させるための小さなmarginがある
          marginTop: 0,
        },
        input: {
          paddingTop: "10px",
          paddingBottom: "8px",
          height: "auto",
        },
        notchedOutline: {
          // デフォルトだと、 position が absolute、
          // ラベルをはみ出させるため上に少しの余白がある
          top: 0,
          "legend" : {
            // 内包された legend 要素によって、四角の左側の切り欠きが実現されているので、
            // 表示されないように。
            // (SCSS と同様にネスト記述が可能です。)
            display: "none",
          },
        },
      },
    },
    MuiFormHelperText: {
      styleOverrides: {
        root: {
          // フォーム下部のテキスト、エラーメッセージ
          // お好みで左余白を無くしています。
          marginLeft: 0,
        },
      },
    },
  },
});

コメントアウトされている、typography.subtitle2 という形の指定には「テーマの Composition」という手法を用います。 公式ドキュメント の "Theme composition: using theme options to define other options" の項目に詳しく書かれています。

テーマ機能によるコンポーネントのカスタマイズ

テーマ機能を使ったコンポーネントのカスタマイズは、
components > Mui(コンポーネント名) > styleOverrides > (CSS ルール) > {スタイルの記述}
のような階層構造で記述します。

const theme = createTheme({
  components: {             // コンポーネントたちのスタイルを上書きする
    MuiOutlinedInput: {     // OutlinedInput コンポーネント
      defaultProps: {       // Prop のデフォルト値の上書き
        type: "text"
      },
      styleOverrides: {     // CSS によるスタイルの上書き
        root: {             // CSSルール "root" が対象
          marginTop: 0,
        },
        input: {            // CSSルール "input" が対象

InputLabel, OutlinedInput, FormHelperText って何?

「なんで TextField じゃないの? InputLabel, OutlinedInput, FormHelperText って何?」

とお思いと思います。

まず、 TextField インプットは、それ自体に何らかのスタイルが当てられているコンポーネントではありません。
次の複数の組み合わされたコンポーネントによって構成された Compound Component (複合的コンポーネント) です。

  • FormControl
    • InputLabel
    • OutlinedInput (variant="outlined" の場合)
    • FormHelperText

ドキュメントの下記の章に、それらのコンポーネントについて軽く説明されています。

CSS ルールについて

ところで、それぞれのコンポーネントについて、root, notchedInput のような「CSSルール」に対してスタイルが当てられているのですが、この「CSSルール」とは何なのでしょうか?

MUI のドキュメントには、Component のドキュメントと、APIのドキュメントとがあり、 Component のドキュメントの末尾には API という章が立てられて、複数のコンポーネントのAPIへのリンクが書かれています。

例: TextField コンポーネントの "API" 章
image.png

そして、それぞれのAPIページにある "CSS" の章を参照してみましょう。
例: OutlinedInput の "CSS" の章
image.png

"Rule name" のカラムに書かれているのが、今回の「テーマによるカスタマイズ」に使われている CSSルール名になります。
(それぞれの説明はDescription に書かれている英文を見れば何となく分かりますよね?)

DevTools を見ながら実際のスタイルを編集する

最後は作業です。根性です。

DevTools を使って実際の要素に当てられたスタイルを確認しつつ、テーマの CSS を上書きしていきましょう。
スタイルの確認には実際の class 名が必要ですが、これには CSS の表の Global class のカラムの文字列が相当します。

32
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?