opsinjs
ComponentsPatternsForm design

Required and optional

Mark one or the other but never both. In a health product, prefer marking optional, because it makes the cost of every required field visible.

When to use

Read this once, decide once, and apply the decision to every form in the product. The failure here is not choosing wrongly; it is choosing twice.

There are three defensible conventions:

  1. Mark required fields. Sensible when most fields are optional.
  2. Mark optional fields. Sensible when most fields are required. That is the normal case in a health product, because a form that asks for things it does not need should have had the fields removed.
  3. Mark nothing, because everything is required. Only honest when it is true, and it is worth stating in the intro that it is true.

opsinjs recommends (2), marking optional, for a specific reason: it makes each required field carry its own justification. When "optional" is the marked case, adding a required field is a visible act. When "required" is the marked case, the asterisks multiply and nobody notices.

When not to use

  • Do not apply this to consent. Consent is never "required" in the form sense. If the reader cannot decline, it is not consent. See Consent and permissions.
  • Do not apply it to a validated instrument. Its own instructions govern which items may be skipped, and re-labelling them is a change to the instrument.
  • Do not use it as an alternative to deleting the field. The first question is always whether to ask at all. See Form design and each page in Ask users for….
  • You want the code. Schema-level requiredness is Handbook → Forms.

How it works

Diagram source (mermaid)
flowchart TD
A["A field on the form"] --> B{"Can the reader proceed without it?"}
B -->|"no"| C{"Is that genuinely true, or just convenient for us?"}
C -->|"convenient"| D["Make it optional, or remove it"]
C -->|"genuinely required"| E["Leave it unmarked under the marked-optional convention"]
B -->|"yes"| F["Label it 'optional' in the visible label text"]
F --> G{"Does skipping change what the reader gets?"}
G -->|"yes"| H["Say what changes, next to the field"]
G -->|"no"| I["No further explanation needed"]

Rules:

  • The word, not a symbol. "(optional)" in the visible label. An asterisk is a convention the reader has to be taught, is frequently not announced, and is usually explained in a legend they scrolled past.
  • The marker is inside the label element, so it is part of the accessible name: "Notes (optional)".
  • Never mark both. A form with asterisks on required fields and "(optional)" on the others has two systems and is ambiguous about the fields carrying neither.
  • required on the control matches the label. The visual and the programmatic must agree; if the schema says required and the label says optional, the reader finds out at submit.
  • Skipping has a stated consequence when there is one. "Optional. Without it we'll compare your readings to a general adult range rather than one for your age" is a decision. A bare "(optional)" on a field that quietly degrades the product is not.
  • Do not fake requiredness to improve data quality. Making a field required because the analytics team wants it produces worse data, not better: readers enter something rather than nothing.

Content

Do

Label: "Anything else you want to add (optional)". The word is in the label, the reader needs no legend.

Don’t

Label: "Notes" with a small grey asterisk beside "Weight" three fields up and a note at the top reading "* indicates a required field".

Do

"Your ethnicity (optional). We ask because some reference ranges differ, and it helps us check the product works equally well for everyone. You can skip it."

Don’t

"Ethnicity *" is required, unexplained, and reads as gatekeeping in a health context. See Ethnicity.

Accessibility

  • The marker is in the accessible name. Screen-reader users hear "Notes, optional, edit text" without needing to have found a legend.
  • Use the required attribute (or aria-required where the native attribute is unavailable) so the state is programmatically determinable, and make sure it matches the label.
  • An asterisk with no accessible text is meaningless. If a design demands one, the label must still contain the word, and the asterisk must be decorative.
  • Do not rely on colour or weight to distinguish required from optional; WCAG 2.2 SC 1.4.1 and the general colour-independence rule both apply. See Colour independence.
  • Do not announce requiredness twice. A label containing "(required)" and the required attribute produces a double announcement in several combinations. Under the marked-optional convention this does not arise, which is a further small argument for it.
  • Requiredness must not be discovered only at submit. WCAG 2.2 SC 3.3.2 (Labels or Instructions) is the floor.

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.

On this page