Skip to content
Navigation

Forms

Layout, validation and submission rules — extracted from our most conversion-tested checkout.

Structure

  • Single page over a multi-step wizard when conversion matters — payment methods visible immediately; accordions hide data and create doubt about what is saved.
  • When most fields are required, mark the optional minority with “(optional)” — don’t asterisk everything.
  • Placeholders are format hints only (“+420 …”), and only where the format isn’t obvious. Never use a placeholder as the field label.

Submit

  • The submit is the surface’s primary (variant="default"). Placement: full-width on narrow stacked forms; directly right of the input in inline apply rows; in a multi-step flow it lives in the flow’s action bar, not inside the form.
  • High-stakes submits (payment, binding offers): disabled until valid, with the reasons visible — tooltip listing blockers or a readiness checklist. Simple forms (contact): keep the submit enabled and validate on submit.
  • Busy: disable + progressive label (“Sending…”) + spinner when the wait is noticeable.

Validation

  • Validate on blur and on submit; clear a field’s error on the first keystroke; synchronous, no debounce.
  • On submit with errors: scroll to and focus the first invalid field.
  • Error copy is action-oriented and unique per field (“Enter a company name”, not “This field is required”).
  • Wire it up: aria-invalid + aria-describedby on the field, role="alert" on the message. [a11y]
  • docs/patterns/action-hierarchy.md — where the submit sits among other actions.
  • docs/components/button.md — busy and disabled states.