React
Form shadcn con react-hook-form
Dichiari lo schema Zod, monti Form con useForm e lasci che FormField colleghi input, errore e attributi ARIA. Le classi shadcn restano intatte.
In sintesi
- Lo schema Zod è la sola fonte di verità: il form legge i suoi errori, non li riscrive.
- FormField collega input, messaggio e attributi ARIA, quindi FormControl non va sostituito.
- react-hook-form 7.91.0 e zod 4.6.7 sono entrambi MIT e vanno installati a parte.
Risposta breve: installa react-hook-form, zod e @hookform/resolvers, dichiara lo schema e monta Form con useForm. Ogni FormField collega input, messaggio di errore e attributi ARIA.
Lo schema prima del form
import { z } from "zod";
export const signupSchema = z.object({
email: z.email(),
password: z.string().min(12, "Almeno 12 caratteri"),
});
export type SignupValues = z.infer;
Lo schema fa due lavori: valida i valori a runtime e produce il tipo SignupValues a compile time. Il resolver traduce il risultato di Zod nel formato che react-hook-form si aspetta, quindi gli errori arrivano già associati al campo.
Il form completo
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { signupSchema, type SignupValues } from "./schema";
export function SignupForm() {
const form = useForm({
resolver: zodResolver(signupSchema),
defaultValues: { email: "", password: "" },
mode: "onBlur",
});
return (
console.log(values))} noValidate>
(
Email
)}
/>
Crea account
);
}
Tre dettagli tengono in piedi il tutto: Form pubblica il contesto del form, FormControl aggiunge aria-invalid e aria-describedby quando c'è un errore, e FormMessage stampa il messaggio solo se quel campo è invalido.
Cosa fa FormField al posto tuo
- Un solo render per tasto: il campo aggiorna se stesso, non il form intero, perché
Controlleriscrive la sottoscrizione al singolo nome. - Collegamento accessibile: etichetta, descrizione ed errore arrivano al campo tramite id generati, quindi lo screen reader li legge.
- Stato tipizzato:
controlconosce il tipo diSignupValues, e un nome sbagliato diventa un errore di compilazione.
Il comando
npx shadcn@latest add form input button
npm install react-hook-form zod @hookform/resolvers
Record vivi nel catalogo
Il risultato si confronta con record già pubblicati: la libreria shadcn, il blocco form-layout-01 con etichette e colonne, e la categoria blocchi form. Ogni record indica licenza e sorgente.
La limitazione
Lo schema valida nel browser, non sul server: la stessa regola va rieseguita lì, altrimenti basta una richiesta costruita a mano per saltarla. Il form monta con noValidate, quindi la validazione nativa del browser resta spenta e i messaggi sono solo quelli che scrivi tu.
Dove continuare
L'installazione dei componenti è in come installare shadcn/ui; la stessa validazione lato server è in Server Actions e validazione; il confronto fra le librerie di form è in librerie di form React. Per i token di stile leggi come tematizzare shadcn/ui.
Domande frequenti
Devo installare react-hook-form e zod a mano?
Sì. Il comando shadcn aggiunge solo i componenti di interfaccia; react-hook-form, zod e il resolver sono dipendenze del progetto e vanno installati con npm.
Posso usare Form senza Zod?
Sì. Form accetta qualsiasi resolver compatibile con react-hook-form, per esempio Yup o Valibot, oppure le regole inline. Zod aggiunge il tipo dedotto dallo schema, che con le regole inline non hai.
Perché FormMessage resta vuoto?
Perché il campo non è ancora stato validato, di solito per un mode troppo pigro o per il nome che non combacia. Controlla il mode di useForm e il name di FormField.
Come mostro un errore che arriva dal server?
Con form.setError sul nome del campo, dopo la risposta. Il messaggio entra nello stesso canale di FormMessage, quindi non serve un secondo componente per gli errori remoti.
Il form funziona senza JavaScript?
No. react-hook-form valida e invia nel browser, quindi senza JavaScript il submit non parte. Per un form che funziona senza JavaScript serve un form HTML con action lato server.