Skip to content

Patterns

Forms and validation

A good form asks for little, says its rules up front, stays quiet while the reader types and, when something is wrong, says exactly where and how to fix it.

The validation flowLink to the section The validation flow

  1. Before typing

    Say the rules in the description, such as “Up to 40 characters”, so nobody learns them from an error.

  2. While typing

    Stay quiet. An error for a field the reader is still filling in is noise.

  3. On leaving a changed field

    Check that field and show its error inline. Leave untouched fields alone.

  4. On submit

    Check everything. Show each error under its field and a FormErrorSummary at the top, which takes focus and links to each field.

  5. While fixing

    Update each inline error as the reader types. The summary stays as it was until the next submit, so focus never jumps.

  6. After success

    Say what happened, next to the button with FormActions, in a toast, or as a flash message on the next page.

Try it: submit empty, then fix the fields
The invitation goes to this address.
Up to 40 characters.
Role
Can change billing and remove people
The partstsx
<form noValidate onSubmit={submit}>
  {summary.length > 0 && <FormErrorSummary title={t('form.problems', { count: summary.length })} errors={summary} />}
  <TextField id="email" label={t('email')} type="email" autoComplete="email" isRequired
    onBlur={check('email')} isInvalid={!!errors.email} errorMessage={errors.email} />
  <FormActions status={status}>
    <Button type="submit" isPending={sending} pendingLabel={t('sending')}>{t('send')}</Button>
  </FormActions>
</form>

Labels, hints and marksLink to the section Labels, hints and marks

  • Every field has a visible label above it. A placeholder is an example, never the label: it disappears while typing.
  • Mark the smaller group. When most fields are required, mark the optional ones with optionalLabel; otherwise mark the required ones. requiredLabel replaces the asterisk with a word.
  • Put rules in description. It is linked to the field, so a screen reader reads it after the label.
  • Use status for good news and hints that arrive while typing, such as “Name is free”, in the ok, info or warn tone.
Up to 80 characters. You can change it later.
Do. Give the rule before it can be broken.
Don’t. Hide the label and the rule in a placeholder that vanishes on the first key.

Types and autocompleteLink to the section Types and autocomplete

The right type brings the right keyboard on phones, and autocomplete lets browsers and password managers fill the field, which WCAG asks for on personal data.

Common fields with their type and autocomplete value
FieldtypeautoComplete
Full nametextname
Emailemailemail
Phoneteltel
Current passwordpasswordcurrent-password
New passwordpasswordnew-password
One-time codetext, inputMode="numeric"one-time-code
Organisationtextorganization
Postal codetextpostal-code

Layout from 320pxLink to the section Layout from 320px

  • One column, about 32rem wide at most. The eye moves down, not in a zigzag.
  • Two fields share a row only when they belong together and are short, such as a postal code and a city, and only from the sm breakpoint up.
  • Group related fields in a fieldset with a legend, or use CheckboxGroup and RadioGroup, which do it for you.
  • FormActions puts the main button last on wide screens and stacks the buttons at full width on narrow ones, main button on top.
  • A long form keeps its buttons in view with sticky.

Density in formsLink to the section Density in forms

Forms on the web keep the comfortable density: 36px controls and room between fields. The compact density is for the desktop tools, where many settings sit on one screen. Both keep targets above 24px, and field text stays at 16px on phones so iOS does not zoom.

See it in actionLink to the section See it in action

Sending empty shows every problem at once; fixing the fields clears them.

Search this site

Arrows move through the results, Enter opens one, Esc closes. Ctrl K /