01 — Foundation

Forms reveal quality immediately

Good forms help people finish. Bad forms create abandonment, support tickets, and broken trust.

Forms are where accessibility and UX stop being abstract. Users need to understand what is required, complete fields confidently, recover from mistakes, and submit without guessing what happened.

This pattern describes practical expectations for modern forms — real completion, not decorative form theatre. Where our guidance matches UK public-sector practice, we align with the GOV.UK Design System — especially its validation pattern and form components, which are heavily tested with disabled users, assistive technology, and real services.

You do not need GOV.UK Frontend CSS to follow the same behaviour: labels, hints, error summaries, focus management, and plain language work in any stack.

02 — Principles

Help users succeed

The purpose of a form is not collecting data — it is helping someone complete a task.

  • explain requirements before users fail them — see labels, legends, and headings
  • reduce effort with labels, types, and autocomplete
  • show clear errors that say how to fix the problem — same wording in the summary and beside the field
  • keep keyboard flow logical with visible focus
  • work before JavaScript enhancement

03 — Labels

Labels are mandatory

Every control needs a real label — not a placeholder, not a visual guess.

GOV.UK is explicit: do not use placeholder text in place of a label. Follow the same rule — see text input guidance.

Good example

<label for="email">
    Email address
</label>

<input
    id="email"
    name="email"
    type="email"
    autocomplete="email"
>

Placeholders are not labels

Placeholders can show examples or format hints. They should not replace labels — they disappear while typing, often have weak contrast, and increase cognitive load.

Bad

<input placeholder="Email address">

04 — Hints

Hint text and aria-describedby

Hints explain what to enter or how data is used — linked to the field for screen readers.

Put hint text between the label and the control (or immediately after the legend for grouped inputs). Give the hint an id and reference it from the input with aria-describedby — the same approach as GOV.UK text inputs with hint text.

<label for="email">
    Email address
</label>

<p id="email-hint" class="hint">
    We will only use this to send you a receipt
</p>

<input
    id="email"
    name="email"
    type="email"
    autocomplete="email"
    aria-describedby="email-hint"
>

When a field has an error, include both hint and error IDs in aria-describedby so assistive technology reads the full context.

05 — Inputs

Types, autocomplete, and grouping

The browser already helps with validation, keyboards, and autofill — use it.

Correct input types

type="email"
type="tel"
type="url"
type="password"
type="date"

This improves validation, mobile keyboards, autofill, and accessibility without custom widgets. For email-specific flows, see GOV.UK email addresses.

Autocomplete

autocomplete="email"
autocomplete="given-name"
autocomplete="family-name"
autocomplete="postal-code"

Group related fields

  • use fieldset and legend for addresses, payment blocks, and radio or checkbox groups
  • mark required fields clearly — not colour alone; GOV.UK uses “(optional)” on non-required fields where that reduces noise
  • prefer date input over custom date pickers unless you can match native keyboard and screen reader behaviour
<fieldset>
    <legend>Contact preferences</legend>
    <!-- checkboxes or radios -->
</fieldset>

<label for="email">
    Email address
</label>

<input id="email" name="email" type="email" required autocomplete="email">

06 — Errors

Recover from validation errors

Follow the GOV.UK validation pattern: summary at the top, message on each field, focus moved to the summary.

When server-side validation fails, GOV.UK requires both an error summary and an error message beside every invalid answer. We expect the same — see the full validation pattern.

Error summary

  • Show a summary at the top even when there is only one error
  • Use a clear heading — GOV.UK uses “There is a problem”
  • Link each list item to the field anchor (#field-id)
  • Move keyboard focus to the summary on load (tabindex="-1"on the summary container if you manage focus in script)
  • Use the same error text in the summary and next to the field
  • Prefix the page <title> with “Error: ” so screen readers announce failure immediately
  • prefix field errors with <span class="vh">Error:</span>when the visible message omits the word — use .vh, not.is_hidden, so assistive technology still reads it
<div class="error-summary" role="alert" tabindex="-1">
    <h2>There is a problem</h2>
    <ul>
        <li>
            <a href="#email">Enter an email address</a>
        </li>
    </ul>
</div>

<label for="email">Email address</label>

<p id="email-hint" class="hint">Example: name@example.com</p>

<p id="email-error" class="error-message">
    <span class="vh">Error:</span>
    Enter an email address
</p>

<input
    id="email"
    name="email"
    type="email"
    autocomplete="email"
    aria-describedby="email-hint email-error"
    aria-invalid="true"
>

Clear messages

Too vague

'Invalid input'

Clearer

'Enter a valid email address'

Placement and timing

  • show errors beside the relevant field, consistently positioned
  • link errors to fields with aria-describedby and aria-invalid="true"
  • avoid aggressive validation while users are still typing
  • after failure, move focus to the summary or first invalid field

07 — Keyboard

Keyboard, focus, and recovery

Forms must be completable without a pointer — and failures must be obvious.

  • logical tab order and visible focus on every control
  • Enter submits; users are not trapped in overlays
  • after failure, move focus to the error summary or first invalid field — same as GOV.UK error summary behaviour
  • never remove focus outlines without a stronger replacement

Bad

*:focus {
    outline: none;
}

Screen reader users need clear names, required state, and validation feedback announced when it matters — not only visual colour changes.

08 — Guidance

Passwords, uploads, and custom controls

Reduce mistakes with clear guidance — and prefer native controls unless custom UI earns its complexity.

  • show password rules before submission, not only after failure
  • file uploads: visible label, accepted types, and errors in plain language — see GOV.UK file upload
  • test custom comboboxes, date pickers, and selects with keyboard and screen readers
  • use large touch targets and sensible spacing on mobile

If styling a native customisable select with ::picker(select), keep the classic select as the fallback and document the support gate; see the LSCSS browser support guidance.

09 — Resilience

Motion, save states, and progressive enhancement

Calm validation, clear save behaviour, and forms that work without JavaScript.

Avoid dramatic animated validation. Respect reduced-motion preferences. Long forms may need autosave or drafts — but users should know when data is saved and what still needs submitting. Silent assumptions create anxiety.

Forms should submit and return useful feedback before enhancement runs. JavaScript should improve the experience, not justify whether the form functions at all. Heavy validation frameworks often hurt accessibility and performance on mobile and older hardware.

@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

10 — Anti-patterns

What to avoid

Familiar mistakes that still ship in production.

  • placeholders used as labels
  • invisible focus states
  • validating every keystroke on long fields
  • error messages that announce failure without a fix
  • only inline errors with no summary — GOV.UK always shows both
  • giant custom form frameworks where native HTML already works

11 — Review

Before you approve

A short checklist for accessible forms in code review — aligned with GOV.UK validation.

  • every field has a proper label
  • hints use id and aria-describedby where needed
  • correct type and autocomplete where appropriate
  • failed submit shows error summary plus field messages; wording matches
  • focus moves to summary or first error; page title prefixed with “Error: ”
  • aria-invalid and aria-describedby include error IDs on invalid fields
  • keyboard navigation works end to end
  • form works on mobile and without JavaScript

When in doubt, compare against the GOV.UK validation pattern and ask: Does this form help users succeed, or merely collect data? If the answer is “collect data”, the form is not finished.

Common questions

Must every form control have a visible label?

Yes. Placeholder text is not a label. Use a label element, or aria-labelledby when the design ties text to the control in a way assistive tech can follow.

Where should validation errors appear?

Next to the field and in a summary at the top of the form for longer flows. Announce errors with text, not colour alone, and move focus to the summary or first invalid field.

Should forms work without JavaScript?

The baseline submit and error handling should work from HTML and server responses. Enhance with client-side validation for speed, not as the only path.