/** * Basic Form Example - Login/Signup Form * * Demonstrates: * - Simple form with email and password validation * - useForm hook with zodResolver * - Error display * - Type-safe form data with z.infer * - Accessible error messages */ import { useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' // 1. Define Zod validation schema const loginSchema = z.object({ email: z.string() .min(1, 'Email is required') .email('Invalid email address'), password: z.string() .min(8, 'Password must be at least 8 characters') .regex(/[A-Z]/, 'Password must contain at least one uppercase letter') .regex(/[a-z]/, 'Password must contain at least one lowercase letter') .regex(/[0-9]/, 'Password must contain at least one number'), rememberMe: z.boolean().optional(), }) // 2. Infer TypeScript type from schema type LoginFormData = z.infer export function BasicLoginForm() { // 3. Initialize form with zodResolver const { register, handleSubmit, formState: { errors, isSubmitting, isValid }, reset, } = useForm({ resolver: zodResolver(loginSchema), mode: 'onBlur', // Validate on blur for better UX defaultValues: { email: '', password: '', rememberMe: false, }, }) // 4. Handle form submission const onSubmit = async (data: LoginFormData) => { try { console.log('Form data:', data) // Make API call const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { throw new Error('Login failed') } const result = await response.json() console.log('Login successful:', result) // Reset form after successful submission reset() } catch (error) { console.error('Login error:', error) } } return (

Login

{/* Email Field */}
{errors.email && ( {errors.email.message} )}
{/* Password Field */}
{errors.password && ( {errors.password.message} )}
{/* Remember Me Checkbox */}
{/* Submit Button */} {/* Form Status */}
{isValid && !isSubmitting && ( Form is valid ✓ )}
) } /** * Signup Form Variant */ const signupSchema = loginSchema.extend({ confirmPassword: z.string(), name: z.string().min(2, 'Name must be at least 2 characters'), }).refine((data) => data.password === data.confirmPassword, { message: "Passwords don't match", path: ['confirmPassword'], }) type SignupFormData = z.infer export function BasicSignupForm() { const { register, handleSubmit, formState: { errors, isSubmitting }, } = useForm({ resolver: zodResolver(signupSchema), defaultValues: { name: '', email: '', password: '', confirmPassword: '', rememberMe: false, }, }) const onSubmit = async (data: SignupFormData) => { console.log('Signup data:', data) // API call } return (

Sign Up

{/* Name Field */}
{errors.name && ( {errors.name.message} )}
{/* Email Field */}
{errors.email && ( {errors.email.message} )}
{/* Password Field */}
{errors.password && ( {errors.password.message} )}
{/* Confirm Password Field */}
{errors.confirmPassword && ( {errors.confirmPassword.message} )}
) }