Material-UIでテキストフィールドをカスタマイズして実装する方法


こんにちは、 Gaji-Labo アシスタントエンジニアの石垣です。

今回は Material-UI でテキストフィールドを作る際にいくつかハマった点があったため、テキストフィールドの作成方法についてまとめたいと思います。

Material-UI でのテキストフィールドの作成方法

Material-UI には標準で TextField というコンポーネントが用意されており、 import するだけで Material Design 準拠のテキストフィールドを使用することができます。

公式ドキュメントの TextField の解説

ただし、TextField コンポーネントにはフィールドのラベル、フィールド本体、ヘルパーテキストの全てが同梱されているため、パーツそれぞれで細かいスタイル変更や挙動の変更を行おうとすると大変な手間がかかります。

TextField コンポーネント自体が FormControlFormLabelOutlinedInput などのコンポーネントが組み合わさって構成されているため、それぞれを単体で使用することでカスタマイズを行うことができます。

たとえば、TextField ではデフォルトでは Material Design に準拠してフィールドのラベルがフィールド内に表示されており、フォーカス時に外側に移動するような挙動となっていますが、ラベルが常に外側に表示されているテキストフィールドを作成するには以下のように実装します。

import React from "react";

import {
  FormControl,
  FormLabel,
  FormHelperText,
  OutlinedInput,
} from "@material-ui/core/";
import { createMuiTheme, ThemeProvider } from "@material-ui/core/styles";

/* ... */

export function TextField({
  error,
  disabled,
  label,
  id,
  name,
  type,
  placeholder,
  required,
  onBlur,
  defaultValue,
  helperText,
}) {
  /* ... */

  const theme = createMuiTheme({
    overrides: {
      MuiFormControl: {
        /* 全体のスタイル */
      },
      MuiFormLabel: {
        /* ラベルのスタイル */
      },
      MuiOutlinedInput: {
        /* フィールドのスタイル */
      },
      MuiFormHelperText: {
        /* ヘルパーテキストのスタイル */
      },
    },
  });

  return (
    <ThemeProvider theme={theme}>
      <FormControl error={error} disabled={disabled}>
        <FormLabel>
          <div>{label}</div>
          <OutlinedInput
            fullWidth
            id={id}
            name={name}
            type={type}
            placeholder={placeholder}
            required={required}
            onBlur={onBlur} // onBlur にフィールド変更時のイベントを渡す
            defaultValue={defaultValue} // defaultValue でフィールドの値を持つ
          />
        </FormLabel>
        <FormHelperText>{helperText}</FormHelperText>
      </FormControl>
    </ThemeProvider>
  );
}
実装したテキストフィールドのコンポーネント

フィールドの状態を管理するコンポーネント FormControl で全体をラップし、 FormLabel 内にラベルの要素と OutlinedInput を入れ、 FormHelperText にヘルパーテキストを入れるようにしました。

これでラベルが常に表示されたテキストフィールドを実装することができました。このように分解してから組み合わせることで個別のパーツのカスタマイズが容易になります。

onChange + value ではなく onBlur + defaultValue で値を管理する

以上のコンポーネントでは、 onBlur にフィールド変更時のイベントを渡し、 defaultValue props で値を保持させるという風に実装しています。

最初は onBlur と defaultValue ではなく onChange と value で値を管理するようにしていましたが、この実装方法では入力するごとにフォーカスが外れてしまう問題がありました。これを防ぐために onBlur と defaultValue で実装をしています。

まとめ

今回は Material-UI でのテキストフィールドの作成方法についてまとめました。

TextField のように、Material-UI には他にもいくつかのコンポーネントが組み合わさった形で構成されているコンポーネントがあります。1つ1つを分解して使用することでカスタマイズが容易になります。

今後も Material-UI でのコンポーネント実装方法について知見をブログで共有していきたいと考えています。

Gaji-Laboでは、JavaScriptフレームワーク経験が豊富なパートナーさんを募集しています

Gaji-Laboでは、開発チームの一員としてプロジェクトに一緒に取り組んでくれる業務委託のパートナーさんを募集しています。

現在は特にJavaScriptフレームワーク実践と業務経験が豊富なWebフロントエンドエンジニアを必要としています。React + TypeScript、Vue.js、Next.js、Nuxt.js など、あなたの得意なフレームワークを教えて下さい!

パートナー契約へのお問い合わせもお仕事へのお問い合わせも、どちらもいつでも大歓迎です。まずはオンラインでのリモート面談からはじめましょう。ぜひお気軽にお問い合わせください!

お問い合わせしてみる!

投稿者 Ishigaki Shotaro

未経験から Gaji-Labo に入社。現在は React/TypeScript/Next.js の案件で MUI を使ったコンポーネント組み込みを担当。プロジェクトチームのリードとして共に組み込み作業をしているメンバーの進行管理も行っています。休日はだいたい家で音楽を聴いており、たまにライブに出かけています。