A set of field components built on react-hook-form + Zod. Each field wraps useController internally — the form parent only needs control. No register, no watch, no manual wiring.
Usage
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { InputField, SelectField, TextField } from '@/components/form'
const schema = z.object({
name: z.string().min(1, 'Required'),
role: z.string().min(1, 'Required'),
notes: z.string().min(1, 'Required'),
})
type FormValues = z.infer<typeof schema>
const ROLE_OPTIONS = [
{ value: 'frontend', label: 'Frontend' },
{ value: 'backend', label: 'Backend' },
]
export function MyForm() {
const form = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: { name: '', role: '', notes: '' },
})
return (
<form onSubmit={form.handleSubmit(console.log)}>
<InputField name="name" label="Name" control={form.control} require />
<SelectField name="role" label="Role" control={form.control} options={ROLE_OPTIONS} require />
<TextField name="notes" label="Notes" control={form.control} require />
<button type="submit">Submit</button>
</form>
)
}All fields share name, control, label, require, disabled, className.