Login Form Example
A simple login form using useActionForm with automatic Zod error mapping from the server action.
Source Code
Server Action
'use server'
import { z } from 'zod'
const loginSchema = z.object({
email: z.string().email('Please enter a valid email'),
password: z.string().min(8, 'Min 8 characters'),
})
export async function loginAction(data: z.infer<typeof loginSchema>) {
await new Promise(r => setTimeout(r, 1000)) // simulate delay
const parsed = loginSchema.safeParse(data)
if (!parsed.success) {
return { errors: parsed.error.flatten().fieldErrors }
}
if (parsed.data.email === 'taken@example.com') {
return { errors: { email: ['Already registered'] } }
}
return { success: true }
}Client Component
'use client'
import { useActionForm } from 'hookform-action'
import { loginAction } from './actions'
export function LoginForm() {
const {
register,
handleSubmit,
formState: { errors, isPending, isSubmitSuccessful },
} = useActionForm(loginAction, {
defaultValues: { email: '', password: '' },
})
if (isSubmitSuccessful) return <p>✓ Logged in!</p>
return (
<form onSubmit={handleSubmit()}>
<input {...register('email')} />
{errors.email && <span>{errors.email.message}</span>}
<input {...register('password')} type="password" />
{errors.password && <span>{errors.password.message}</span>}
<button disabled={isPending}>
{isPending ? 'Signing in...' : 'Sign In'}
</button>
</form>
)
}