Pular para o conteúdo

Form validation pattern

patterns specs/patterns/form-validation.kmd

How a form tells the user what is wrong and how to fix it: inline validation on blur, a top-of-form error summary that links to each offending field with a *corrective* message (not just "invalid"), required/optional marking on the label, two-tier helper text, progress on long forms, and an explicit success confirmation. Humanizes messages via the user-facing errors spec. Modeled after the gov.br Padrão Digital and GOV.UK error-summary. Distinct from form-page (which owns the save-bar and sectioning) — this pattern owns the *validation contract*.

Quando este padrão se aplica

Triggers primários

Todos os triggers

Corpo da especificação

Pattern — Form validation

Status: v0.1.0 — Draft. Promoted from the KDS × gov.br Design System gap analysis (tools/design-gen/docs/govbr-ds-gap-analysis.md, GVB-14). Source: gov.br Padrão Digital de Governo (validation + error-summary with corrective action) and GOV.UK Design System error-summary.

R1 — When to use (vs form-page / wizard)

  • Form validation (this): the contract for how any form surfaces errors and success — the field-level and summary-level behavior. It composes onto the other form patterns.
  • Form page (specs/patterns/form-page.kmd): the section-grouped edit surface with the sticky save bar. It hosts this validation contract at Save.
  • Wizard (specs/patterns/wizard-multistep.kmd): per-step gates use this same contract at each step boundary.

R2 — Required / optional marking

  • Mark fields at the label, never only by color or a lone asterisk. The default is to mark the smaller set: if most fields are required, mark the optional ones ("(optional)"); otherwise mark the required ones. State the convention once at the top of the form.
  • The required/optional state is part of the accessible name (announced by screen readers), not a purely visual glyph.

R3 — Two-tier helper text

  • Placeholder is a format hint only (e.g. DD/MM/YYYY) and must never carry the label or a persistent instruction — it vanishes on input.
  • Persistent helper text (below the field) carries anything the user must still see while typing: constraints, examples, why the field is asked. Helper text is associated to the field (aria-describedby).

R4 — Inline validation on blur (not on keystroke)

  • Validate a field when the user leaves it (blur) or on submit — never on every keystroke (which nags mid-entry). Exception: a live constraint the user is actively working toward (password strength, character budget) may update live because it is progress feedback, not a rejection.
  • Once a field has been marked invalid, re-validate it on input so the error clears as soon as it is fixed (don't make the user blur again to see success).

R5 — Corrective messages (the core rule)

  • Every error states what is wrong and how to fix it, not just that the value is invalid. "Enter your date of birth" / "Date of birth must be a real date, like 31/03/1980" — never "Invalid field" or "Error".
  • Messages are humanized per specs/errors/user-facing-messages.kmd (plain language, no codes/stack terms, no blame). The message names the field so it reads standalone in the summary (R6).
  • Inline error text sits next to its field, is announced (aria-describedby + aria-invalid), and never relies on color alone (icon + text).

R6 — Error summary at the top (corrective + linked)

  • On a failed submit, render an error summary at the top of the form: a titled block ("There is a problem") listing every error in field order, each a link that moves focus to the offending field.
  • Each summary entry is the same corrective message as the inline error (R5) — the summary is scannable and actionable, not a generic count.
  • Focus moves to the summary on failed submit; the summary is a labeled region so assistive tech announces it. The summary is empty/absent when the form is valid.

R7 — Progress on long forms

  • A form long enough to scroll past one viewport (or split across steps) shows progress: a step indicator for wizards, or a section/position cue for one-page forms, so the user knows how much remains.
  • Progress is advisory, not a gate — it never blocks the user from jumping to a known section (pairs with wizard-multistep's step nav).

R8 — Success confirmation

  • A successful submit confirms explicitly — a confirmation page (specs/patterns/confirmation-page.kmd), an inline success banner, or a toast for low-stakes saves. Silence after submit is a defect: the user must know it worked and what happens next.
  • Success clears all error state and the unsaved-changes guard (specs/navigation/back-behavior.kmd).

R9 — Accessibility & i18n

  • Errors set aria-invalid and are described by their message; the summary is a focusable labeled region; required/optional is in the accessible name (R2).
  • Nothing is communicated by color alone — icon + text on every error and success state.
  • All chrome (summary title, corrective messages, required/optional labels, helper text, success copy) is translatable per specs/i18n/contract.kmd. Corrective messages must survive translation (no concatenated fragments).

Não-escopo

  • The save-bar / dirty tracking / sectioning (specs/patterns/form-page.kmd).
  • Individual field components (text field, date input, selects).
  • Server-side validation rules and schema (this is the presentation contract; the server is the source of truth for what is valid).
  • Auth-specific error handling (login resolution has its own spec).

Referências