ReactHookFormとMaterial-UI v5でHTML5に頼らないDatePickerを作る


はじめに

  • Material-UIでUIを作る(せっかくなので出たばかりのv5を使いたい)
  • ReactHookFormで入力制御したい

といった条件下で、最初にHTML5に頼った日付入力<TextField type="date">で作ってみたところ
Chromeで表示したら↓のようにラベルの初期表示と"年/月/日"の表示が被って酷いことになっていた。

また、HTML5頼りのDatepickerだとまだうまく動かないブラウザがあるといった情報もちらほら見られたことから
Material-UI LabにあるDatePickerで日付入力を構築してみたのが本記事。
(LabはまだCoreに移せていないものという扱いらしいが、DatePickerについてはHTML5での入力が一般化してきたらCoreに移る前に無くなりそうな予感はしている)

目次

  1. 環境
  2. ソースコード
  3. 機能概要
  4. 参考文献

環境

"@date-io/date-fns": "^2.11.0",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@mui/icons-material": "^5.0.0-rc.1",
"@mui/lab": "^5.0.0-alpha.48",
"@mui/material": "^5.0.0-rc.1",
"date-fns": "^2.24.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-hook-form": "^7.15.3",

ソースコード


Sample.tsx
import { DatePicker, LocalizationProvider } from '@mui/lab'
import DateAdapter from '@mui/lab/AdapterDateFns'
import { Box, Button, TextField } from '@mui/material'
import { format } from 'date-fns'
import { ja } from 'date-fns/locale'
import React from 'react'
import { Controller, useForm } from 'react-hook-form'

// 日付入力フォーム
type InputDateProps = {
  id: string
  label: string
  control: any
  errors: any
}
const InputDate: React.FC<InputDateProps> = ({
  id,
  label,
  control,
  errors,
}) => {
  return (
    <Controller
      name={id}
      control={control}
      rules={{
        //必須入力チェック
        required: '必須入力項目です',
        //入力内容が日付として読み取れない状態を通さないためのチェック
        validate: {
          dateCheck: (value) =>
            value.toString() !== 'Invalid Date' || '日付形式で入力してください',
        },
      }}
      render={({ field }) => (
        <LocalizationProvider dateAdapter={DateAdapter} locale={ja}>
          <DatePicker
            {...field}
            label={label}
            mask="____/__/__"
            renderInput={(params) => (
              <TextField
                {...params}
                margin="normal"
                id={id}
                error={Boolean(errors[id])}
                helperText={errors[id] && errors[id].message}
              />
            )}
          />
        </LocalizationProvider>
      )}
    />
  )
}

//入力項目の使用
const Sample: React.FC<{}> = () => {
  const initValue = {
    date: '',
  }

  const {
    control,
    handleSubmit,
    formState: { errors },
  } = useForm<typeof initValue>({ defaultValues: initValue })

  const onSubmit = (e) => {
    //データ内容確認
    console.log(e)
    //Dateからstringに変換して取得
    console.log(format(e.date, 'yyyy/MM/dd'))
  }

  return (
    <Box p={4}>
      <form onSubmit={handleSubmit(onSubmit)}>
        <Box mb={4}>
          <InputDate id="date" label="日付" control={control} errors={errors} />
        </Box>
        <Button variant="contained" type="submit">
          submit
        </Button>
      </form>
    </Box>
  )
}
export default Sample


機能概要

画面表示

初期表示

日付選択

バリデーション

必須チェック

入力形式チェック

入力データの取得結果


文字列で扱いたかったがDate型で取得される模様
⇒とりあえずonSubmitの処理でyyyy/MM/dd形式にフォーマットして使うことにした

参考文献