•  


React Hook Form - shadcn/ui
Docs
React Hook Form

React Hook Form

Building forms with React Hook Form and Zod.

Forms are tricky. They are one of the most common things you'll build in a web application, but also one of the most complex.

Well-designed HTML forms are:

  • Well-structured and semantically correct.
  • Easy to use and navigate (keyboard).
  • Accessible with ARIA attributes and proper labels.
  • Has support for client and server side validation.
  • Well-styled and consistent with the rest of the application.

In this guide, we will take a look at building forms with react-hook-form and zod . We're going to use a <FormField> component to compose accessible forms using Radix UI components.

Features

The <Form /> component is a wrapper around the react-hook-form library. It provides a few things:

  • Composable components for building forms.
  • A <FormField /> component for building controlled form fields.
  • Form validation using zod .
  • Handles accessibility and error messages.
  • Uses React.useId() for generating unique IDs.
  • Applies the correct aria attributes to form fields based on states.
  • Built to work with all Radix UI components.
  • Bring your own schema library. We use zod but you can use anything you want.
  • You have full control over the markup and styling.

Anatomy

<
Form
>

  <
FormField

    control
={...}

    name
=
"..."

    render
={()
 =>
 (

      <
FormItem
>

        <
FormLabel 
/>

        <
FormControl
>

          {
 /*
 Your form field 
*/
}

        </
FormControl
>

        <
FormDescription 
/>

        <
FormMessage 
/>

      </
FormItem
>

    )}

  />

</
Form
>

Example

const
 form 
=
 useForm
()

 
<
FormField

  control
={
form
.
control
}

  name
=
"username"

  render
={({
 field 
})
 =>
 (

    <
FormItem
>

      <
FormLabel
>
Username
</
FormLabel
>

      <
FormControl
>

        <
Input placeholder
=
"shadcn"
 {...
field
}
 />

      </
FormControl
>

      <
FormDescription
>
This is your public display name.
</
FormDescription
>

      <
FormMessage 
/>

    </
FormItem
>

  )}

/>

Installation

Command

npx
 shadcn-ui@latest
 add
 form

Usage

Create a form schema

Define the shape of your form using a Zod schema. You can read more about using Zod in the Zod documentation .

"use client"

 
import
 {
 z 
}
 from
 "zod"

 
const
 formSchema 
=
 z
.
object
({

  username
:
 z
.
string
().
min
(2).
max
(50),

})

Define a form

Use the useForm hook from react-hook-form to create a form.

"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
:
 "Username must be at least 2 characters."
,

  }),

})

 
export
 function
 ProfileForm
()
 {

  //
 1. Define your form.

  const
 form 
=
 useForm
<
z
.
infer
<typeof
 formSchema
>>({

    resolver
:
 zodResolver
(
formSchema
),

    defaultValues
:
 {

      username
:
 ""
,

    },

  })

 
  //
 2. Define a submit handler.

  function
 onSubmit
(
values
:
 z
.
infer
<typeof
 formSchema
>)
 {

    //
 Do something with the form values.

    //
 ? This will be type-safe and validated.

    console
.
log
(
values
)

  }

}

Since FormField is using a controlled component, you need to provide a default value for the field. See the React Hook Form docs to learn more about controlled components.

Build your form

We can now use the <Form /> components to build our 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
:
 "Username must be at least 2 characters."
,

  }),

})

 
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
>
Username
</
FormLabel
>

              <
FormControl
>

                <
Input placeholder
=
"shadcn"
 {...
field
}
 />

              </
FormControl
>

              <
FormDescription
>

                This is your public display name.

              </
FormDescription
>

              <
FormMessage 
/>

            </
FormItem
>

          )}

        />

        <
Button type
=
"submit"
>
Submit
</
Button
>

      </
form
>

    </
Form
>

  )

}

Done

That's it. You now have a fully accessible form that is type-safe with client-side validation.

This is your public display name.

Examples

See the following links for more examples on how to use the <Form /> component with other components:

      - "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
      - "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
      - 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
      - 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
      Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
       한국   대만   중국   일본