Ask users for a date of birth
Three text fields, not a calendar. First, the question of whether an age band would have done instead.
When to use
Ask for a date of birth when a decision in your product genuinely depends on knowing the reader's exact date rather than their approximate age:
- Identity matching. Linking a record to a clinical system that keys on it.
- Age-dependent reference ranges where the boundary is sharp. Some paediatric measures change materially within a year.
- Eligibility with a legal date boundary, such as a screening programme.
For everything else, ask for an age band. Personalising a general adult range, choosing content, or checking that a reader is over eighteen do not require a date; they require a decade or a threshold. An age band is easier to answer, cheaper to store, and less useful to anyone who should not have it.
When not to use
- You only need to know that they are an adult. Ask that. A yes/no or a single band answers it without collecting a birth date.
- You are asking for a recent date, such as when a symptom started or when a dose was taken. Those have completely different affordances: relative options ("today", "yesterday") beat any date entry. See Symptoms.
- You are asking for a future date. An appointment is a picker problem, and a calendar is the right control there. The argument below is specifically about dates decades in the past.
- You want form-level behaviour. Form design.
How it works
flowchart TD
A["We need age information"] --> B{"Does a decision need the exact date?"}
B -->|"no"| C["Ask for an age band and stop"]
B -->|"yes"| D["Three separate text fields: day, month, year"]
D --> E["Each labelled, numeric keyboard, bday-* autofill tokens"]
E --> F{"Complete?"}
F -->|"partially"| G["Name the missing part, keep what was entered"]
F -->|"yes"| H{"Valid calendar date, not in the future?"}
H -->|"no"| I["Say specifically what is wrong"]
H -->|"yes"| J["Accept; echo it back in full on review"]Three text fields, not a calendar. This is the core recommendation. A date picker is optimised for choosing a date near today; reaching 1962 through one requires many interactions, and the widget's month grid is meaningless for a date the reader knows by heart and could type in four seconds. The three-field approach is what GOV.UK and the NHS service manual both document publicly, and the reasoning holds outside those contexts.
Details that matter:
- Order the fields for the reader's locale. The order is day, month, year in most of the world; month, day, year in the United States. Do not reorder the labels to match a stored format.
- Every part is labelled visibly: "Day", "Month", "Year". Not placeholders.
- Accept a month as digits or as a name. Someone typing "March" or "Mar" has answered the question.
- Four-digit years only. Two-digit year entry is ambiguous at exactly the
wrong place:
26is 1926 for some readers of a health product and 2026 for others. - Do not auto-advance between the parts. It is disorienting, it breaks correction, and it is a common cause of a transposed digit going unnoticed.
- Use
autocomplete="bday-day","bday-month","bday-year"on the three fields, or"bday"on a single field where you use one. These are real tokens in the HTML specification's autofill list and are what WCAG 2.2 SC 1.3.5 points at. - Never derive and display an age the reader did not give you without showing the date it came from. A wrong age from a transposed digit is invisible; a wrong date is not.
Edge cases that are not edge cases
- Unknown or partial dates are real. People adopted, displaced, or born where records are incomplete may know only a year. If your system can accept a year alone, say so; if it cannot, say that too rather than letting the reader invent a day.
- Very old readers exist. A validation rule capping age at 100 will reject genuine users. Set physical bounds, not convenient ones.
- Leap days are real. 29 February is a valid answer and a classic rejection.
- The date does not change. Once given, it should be re-editable but never re-asked; WCAG 2.2 SC 3.3.7.
Content
The example hint shows three numerals because a date of birth is three answers, not one: 27, then 3, then 1985 are the Day, Month and Year fields below the question, never one string typed into a single box.
Do
Heading: "What is your date of birth?" Hint: "For example, 27 3 1985". Day, Month and Year fields below the heading. Reason, one line: "We use this to compare your readings to the range for your age."
Don’t
Label: "DOB*". Placeholder: "dd/mm/yyyy". A calendar icon that opens a picker starting at this month, with no keyboard entry path.
Do
Error: "Your date of birth must include a year." It names the missing part and leaves the day and month as entered.
Don’t
Error: "Invalid date" with all three fields cleared, so the reader starts again.
Accessibility
- The three fields are a
fieldsetwith alegendcarrying the question, so each part is announced in context: "Date of birth, Day". - The hint precedes the inputs and is referenced by
aria-describedbyon the group, so it is heard before the reader starts typing rather than after. - Errors name the part. "Enter a year" is actionable; "invalid" is not (WCAG 2.2 SC 3.3.1 and 3.3.3).
inputmode="numeric"on each field so a phone keypad appears, with the fields still accepting a typed month name where you support it.- No auto-advance, so a reader using a screen reader or switch access can review and correct each part.
- Nothing is cleared on error. Re-entry of correct parts is a WCAG 2.2 SC 3.3.7 failure and a reliable way to lose a reader.
- If you offer a calendar as an alternative, it is additive, keyboard operable, and never the only path.
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.
Ask users for a name
One field wherever possible, no assumptions about structure, and the difference between the name on a record and the name someone wants to be called.
Ask users for sex and gender
Two different questions with two different purposes. Ask the one your product actually needs, and never let one field answer both.