React Hook Form + Zod
Integration with React Hook Form using the Zod schema for automatic validation.
npm install rut-kit zod react-hook-form @hookform/resolverspnpm add rut-kit zod react-hook-form @hookform/resolversbun add rut-kit zod react-hook-form @hookform/resolversBasic Validation
The simplest way to integrate rut-kit with React Hook Form is using the Zod resolver. The schema validates automatically and error messages appear in errors.
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { rutSchema } from 'rut-kit/zod'
const schema = z.object({
rut: rutSchema
})
function Form() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
mode: 'onSubmit',
reValidateMode: 'onSubmit',
defaultValues: { rut: '' }
})
return (
<form onSubmit={handleSubmit(console.log)}>
<input {...register('rut')} />
{errors.rut && <span>{errors.rut.message}</span>}
<button type='submit'>Submit</button>
</form>
)
}When the form submits successfully, data.rut is already formatted and validated.
TIP
Use rutSchema with reValidateMode: 'onSubmit' to avoid premature errors while the user is typing. If the field is required, validate it on onSubmit or use a wrapper schema.
Real-Time Validation
If you want the input to show the formatted RUT while the user types, there are two main approaches:
Destructuring onChange
Extract the onChange from register and combine it with formatRut:
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { rutSchema } from 'rut-kit/zod'
import { formatRut } from 'rut-kit'
const schema = z.object({
rut: rutSchema
})
function Form() {
const { register, handleSubmit, setValue, formState: { errors } } = useForm({
resolver: zodResolver(schema),
mode: 'onSubmit',
reValidateMode: 'onSubmit',
defaultValues: { rut: '' }
})
const { onChange, ...rest } = register('rut')
return (
<form onSubmit={handleSubmit(console.log)}>
<input
{...rest}
onChange={async (e) => {
const formatted = formatRut(e.target.value, 'formatted')
setValue('rut', formatted, { shouldValidate: false })
await onChange(e)
}}
/>
{errors.rut && <span>{errors.rut.message}</span>}
<button type='submit'>Submit</button>
</form>
)
}Features:
- More direct with less code
- Perfect for simple transformations
- You must call
onChange(e)manually to maintain React Hook Form's state
Controller
Use React Hook Form's Controller component for more control:
import { useForm, Controller } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { rutSchema } from 'rut-kit/zod'
import { formatRut } from 'rut-kit'
const schema = z.object({
rut: rutSchema
})
function Form() {
const { control, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
mode: 'onSubmit',
reValidateMode: 'onSubmit',
defaultValues: { rut: '' }
})
return (
<form onSubmit={handleSubmit(console.log)}>
<Controller
name='rut'
control={control}
render={({ field }) => (
<input
{...field}
onChange={(e) => {
const formatted = formatRut(e.target.value, 'formatted')
field.onChange(formatted)
}}
/>
)}
/>
{errors.rut && <span>{errors.rut.message}</span>}
<button type='submit'>Submit</button>
</form>
)
}Features:
- Official React Hook Form approach
- Greater control over field behavior
- Better for integrating with third-party UI libraries (Material UI, Base UI, etc.)
field.onChange()automatically handles internal state
TIP
Use formatRut(value, 'formatted') to show the RUT with dots and dash (12.345.678-9) while the user types. The Zod schema will normalize the format when submitting the form.