Form design
How many questions per page, when validation fires, and how errors are surfaced. The behaviour of a question, as distinct from the code that wires a form up.
There are two entirely different questions hiding behind the word "forms", and most design systems answer only one of them.
How a form is wired is a Field bound to React Hook Form, a resolver, a
submit handler, and server errors mapped back onto controls. That is mechanics,
and it lives in Handbook → Forms.
How a question behaves covers whether it shares a page with five others, whether the error appears while the reader is still typing, and whether "optional" is marked or "required" is. That is design, and it is what this group is for. It is also where the majority of real form failures happen, because the wiring is usually correct and the behaviour is usually inherited from whatever the last team did.
When to use
Read this group when you are deciding any of the following:
- How many questions belong on one page, and what to do about the reader's sense of progress if the answer is "one".
- When validation should run and what that decision costs a reader using a screen reader. The timing can be on keypress, on blur, on submit, or some combination.
- Where an error is announced, how the reader gets to it, and what happens to everything else they had typed.
- Whether to mark required fields, optional fields, or neither.
- Which input type and which
autocompletetoken a field should carry. - How to accept a number that has a unit attached to it.
For the specific data a health product actually asks for, such as a date of birth, a name or a set of medications, go to Ask users for…, which applies everything here to one field at a time.
When not to use
- You want the code. Field composition, validation libraries and server error mapping are Handbook → Forms.
- You want the component contract. The parts, states and accessible naming of a single field are Field.
- You want the words. Label and error wording is Content & language; sensitive phrasing is Asking sensitive questions.
- You are collecting a reading, not answering a question. Repeated numeric entry is optimised differently. See Daily logging.
- It is a consent decision. Consent is not a form field, however it is rendered. See Consent and permissions.
How it works
Every page in this group answers one decision, and the decisions compound in a fixed order. Making them out of order is how forms end up with an error summary that nobody can reach and a required-field convention that contradicts itself.
flowchart TD
A["A thing you need to know"] --> B{"Do you need it at all?"}
B -->|"no"| C["Do not ask. This is the largest single win."]
B -->|"yes"| D["Question pages: how many per screen"]
D --> E["Required and optional: what is marked and how"]
E --> F["Autocomplete and input types: what the field is"]
F --> G["Units and numeric entry: what shape the answer has"]
G --> H["Validation timing: when the check runs"]
H --> I["Error summaries: what happens when it fails"]The first branch is the one worth defending. Every field you do not ask for is a field that cannot be mistyped, cannot fail validation, cannot be stored, cannot leak and does not need a retention policy. In a health product this is not a performance argument, it is a risk argument.
Content
Form copy is owned elsewhere, and this group deliberately does not restate it. What these pages do specify is where each piece of copy goes and when the reader meets it: the label before the control, the hint before the input rather than after it, the error adjacent to the field and repeated in the summary, and the unit visible rather than implied.
Accessibility
Forms are where WCAG has the most to say and where most of it is straightforwardly achievable. The success criteria that recur across this group:
- 3.3.2 Labels or Instructions requires a visible label on every control.
- 3.3.1 Error Identification requires errors to be identified in text, not by colour or an icon alone.
- 3.3.3 Error Suggestion requires a knowable fix to be offered.
- 3.3.7 Redundant Entry requires that the reader does not re-enter information they have already given in the same process.
- 1.3.5 Identify Input Purpose requires fields about the reader to carry
the right
autocompletetoken. - 4.1.3 Status Messages requires validation results to reach assistive technology without stealing focus.
- 2.5.8 Target Size (Minimum) requires controls to be at least 24 by 24 CSS pixels; opsinjs targets the stricter 44pt floor in Density and touch targets.
Research
Updates to this page
Last read through against the system on 2026-09-20. Due for review every 12 months; expiry is reported by pnpm run check:freshness.
Sharing with a clinician
Export, summary and hand-off surfaces produce something a clinician can read in ninety seconds without the product implying it has done any interpreting.
Question pages
One question per page or several grouped. How to decide, what one-per-page costs, and the cases in health where grouping is the safer answer.