Handling Forms via Form ActionsEntry 2 of 10

Validating Inside an Action

Checking the submitted values in the action function and collecting error messages to show the user.

Notes

  • Keep rules as small reusable functions in util/validation.ts (isEmail, isNotEmpty, hasMinLength, isEqualToOtherValue).
  • Collect every failure into an errors array, so the user sees all problems at once.
  • An action on its own can't show errors: a plain function's return value goes nowhere. useActionState (Entry 3) turns the return value into state the component can render.
  • A checkbox that isn't checked is missing from FormData, so formData.get('terms') is null. Check formData.has('terms') or formData.get('terms') === 'on'.

What / Why / When

What

Server-style validation, run on submit.

Why

One place to check every rule, including cross-field rules like password confirmation.

When

Any form action that sends data.

Use case

Signup with email, password + confirmation, names, role, terms, and acquisition channels.

Code compare

React
// util/validation.tsexport const isEmail = (value: string) => value.includes("@");export const isNotEmpty = (value: string) => value.trim() !== "";export const hasMinLength = (value: string, min: number) => value.length >= min;export const isEqualToOtherValue = (value: string, other: string) => value === other;

Validation lives on the form model. A cross-field rule (password confirmation) is a group validator.

Angular
// validators.tsexport function equalValues(a: string, b: string): ValidatorFn {  return (group) => (group.get(a)?.value === group.get(b)?.value ? null : { valuesNotEqual: true });}​export function atLeastOneChecked(group: AbstractControl): ValidationErrors | null {  return Object.values(group.value).some(Boolean) ? null : { noneChecked: true };}

Differences and gotchas

  • React validates once, on submit, inside the action. Angular validates continuously and you choose when to show errors (touched, markAllAsTouched()).
  • Validators.requiredTrue is Angular's "checkbox must be checked."
  • Validation in the browser is never enough on its own. Your backend (or a Next.js Server Action) must validate again.

Quick reference

RuleReact (in the action)Angular
EmailisEmail(email)Validators.email
Min lengthhasMinLength(pw, 6)Validators.minLength(6)
Passwords matchisEqualToOtherValue(pw, confirm)Group validator
Terms checkedformData.has('terms')Validators.requiredTrue
At least one checkboxgetAll('acquisition').length > 0Group validator