Docs
React Hook Form

React Hook Form

React Hook FormとZodを使用したフォームの構築.

フォームは扱いが難しいものです。それはウェブアプリケーションにおいて最も一般的に作成するものの1つですが、最も複雑なものの一つでもあります。

適切に設計されたHTMLフォームは:

  • 構造化が良く、セマンティックに正しい。
  • 使いやすくナビゲートしやすい(キーボード)。
  • ARIA属性と適切なラベルでアクセシビリティがある。
  • クライアント側とサーバー側のバリデーションをサポートしている。
  • スタイルが良く、アプリケーションの他の部分と一貫している。

このガイドではreact-hook-formzodを使用してフォームを構築します。 Radix UIコンポーネントを使用して、アクセシビリティのあるフォームを構成するために <FormField> コンポーネントを使用する予定です。

機能

<Form /> コンポーネントはreact-hook-formライブラリのラッパーです。いくつかのことを提供します。

  • フォームを構築するためのコンポーネントを構成します。
  • 制御されたフォームフィールドを構築するための <FormField /> コンポーネント。
  • zodを使用したフォームのバリデーション。
  • アクセシビリティとエラーメッセージを処理します。
  • React.useId()を使用して一意のIDを生成します。
  • 状態に基づいて、フォームフィールドに正しいaria属性を適用します。
  • すべてのRadix UIコンポーネントで動作するように構築されました。
  • 独自のスキーマリブラリを使用します。zodを使用しますが、好きなものを使用できます。
  • マークアップとスタイルを完全に制御できます。

構造

<Form>
  <FormField
    control={...}
    name="..."
    render={() => (
      <FormItem>
        <FormLabel />
        <FormControl>
          { /* フォームフィールド */}
        </FormControl>
        <FormDescription />
        <FormMessage />
      </FormItem>
    )}
  />
</Form>

const form = useForm()
 
<FormField
  control={form.control}
  name="username"
  render={({ field }) => (
    <FormItem>
      <FormLabel>ユーザーネーム</FormLabel>
      <FormControl>
        <Input placeholder="shadcn" {...field} />
      </FormControl>
      <FormDescription>これはあなたの公開表示名です。</FormDescription>
      <FormMessage />
    </FormItem>
  )}
/>

インストール

コマンド

npx shadcn-ui@latest add form

使用

フォームスキーマの作成

Zodスキーマを使用してフォームの形状を定義します。 Zodの使用の詳細については、Zodのドキュメントをご覧ください。

"use client"
 
import { z } from "zod"
 
const formSchema = z.object({
  username: z.string().min(2).max(50),
})

フォームの定義

react-hook-formuseFormフックを使用して、フォームを作成します。

"use client"
 
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
 
const formSchema = z.object({
  username: z.string().min(2, {
    message: "ユーザーネームは少なくとも2文字にしてください。",
  }),
})
 
export function ProfileForm() {
  // 1. フォームを定義します。
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      username: "",
    },
  })
 
  // 2. サブミットハンドラーを定義します。
  function onSubmit(values: z.infer<typeof formSchema>) {
    // フォームの値で何かを行います。
    // ✅ これはタイプセーフで検証済みになります。
    console.log(values)
  }
}

FormFieldは制御されたコンポーネントを使用しているため、フィールドにデフォルト値を指定する必要があります。制御されたコンポーネントの詳細については、React Hook Formドキュメントを参照してください。

フォームを構築する

これで<Form />コンポーネントを使用してフォームを構築できます。

"use client"
 
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
 
import { Button } from "@/components/ui/button"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
 
const formSchema = z.object({
  username: z.string().min(2, {
    message: "ユーザーネームは少なくとも2文字にしてください。",
  }),
})
 
export function ProfileForm() {
  // ...
 
  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
        <FormField
          control={form.control}
          name="username"
          render={({ field }) => (
            <FormItem>
              <FormLabel>ユーザーネーム</FormLabel>
              <FormControl>
                <Input placeholder="shadcn" {...field} />
              </FormControl>
              <FormDescription>
                これはあなたの公開表示名です。
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">送信</Button>
      </form>
    </Form>
  )
}

完了

これで、クライアント側のバリデーションがタイプセーフで、完全にアクセシビリティのあるフォームができました。

This is your public display name.

他のコンポーネントと一緒に<Form />コンポーネントを使用する方法に関する詳細については、次のリンクを参照してください。