Forms and Validation
How whole forms should behave, from labels, keyboards and autofill to validation timing, error messages, real-world data and server errors, and how to test a registration form step by step.
Siobhán O’Brien wants to order groceries. She downloads the app, taps Create account and types her name. “Name can only contain letters.” She tries “Siobhan OBrien”, then her email siobhan+food@mail.ie. “Enter a valid email address.” She gives up and orders from a competitor. Nobody at the company ever hears about it. In the analytics it’s just one more person who “dropped off at sign up”.
Forms are where users give an app something: their name, their address, their money. Every sign up, checkout, booking, support request and profile screen is a form. A broken form doesn’t crash. It quietly turns customers away, which is why testers who know forms well are so valuable.
The quick version
What a good form looks like
- Every field has a visible label above it. A placeholderPlaceholderHint text shown inside an empty input field that disappears when the user starts typing.Open in glossary → disappears when you type, so it can’t be the label.
- Rules and formats are explained before typing (“For example SW1A 1AA”), not only after a mistake.
- Optional fields are marked “(optional)”, related fields are grouped under a heading.
- Each field opens the right keyboard (email, phone pad, numbers) and has an autocomplete hint, so AutoFillAutofillWhen the browser, phone or a password manager fills form fields with saved data in one tap.Open in glossary → and password managers can fill it.
Two layers of validation
input validationInput validationChecking that what the user typed is acceptable before the app uses it.Open in glossary → happens twice. Client-sideClient-side validationChecks that run in the app or browser before data is sent, to give the user quick feedback.Open in glossary → checks run in the app or browser and give quick feedback. Server-sideServer-side validationChecks the server runs on every request, no matter which app or tool sent it. The only validation you can trust.Open in glossary → checks run on the server and are the only ones you can trust, because anyone can skip the app and send data straight to the API. As a tester, check both: a rule that only exists in the app is a bug waiting to happen.
When to show errors
Show an error when the user leaves a field (on blur) or on submit, then update it live while they fix it. Don’t shout while they’re still typing: “Invalid email” after the first letter is rude and useless.
Error messages that help
A good error messageError messageText that tells the user something went wrong and, ideally, how to fix it.Open in glossary → is next to the field, says how to fix it in plain words (“Enter a postcode like SW1A 1AA”), uses text and an icon, not only red, and is announced to screen readers. After an error, everything the user typed stays in the form.
Test real-world data
The world is bigger than “John Smith, 12345”:
- Names:
O'Brien,Đorđe Petrović,Anne-Marie, a single name likeSukarno, very long names. - Emails:
anna+shop@mail.com,anna@mail.co.uk, uppercase letters. - Phones and postcodes:
+44 7700 900123with spaces,SW1A 1AA,1012 AB. - Dates and ages: the 18th birthday today, 29 February.
- Spaces before and after, pasted text, emoji, and decimal commas (
1,5).
Whole-form behavior
Tap Submit twice, submit with the server failing, let the session time out, press Back. The form must not create duplicates, lose the user’s data or show a frozen spinner.
How it works
Behind every Create account or Place order button, the same journey happens:
- The user fills in the form. Typing, picking from lists, pasting, or letting AutoFill do it. The app may check fields as they go (client-side validation).
- The user submits. The app checks everything once more. If something is wrong, it shows the errors and sends nothing.
- The app sends the data. Usually a
POSTrequest with the values in the body, over HTTPS. The submit button shows a loading stateLoading stateWhat the UI shows while it waits for data or an action to finish, such as a spinner or skeleton.Open in glossary → and can’t be used again until there’s an answer. - The server validates again. Same rules, plus checks only the server can do: is this email already registered? Is this postcode one we deliver to? Too many sign ups from this device?
- The server answers. Success (for example
201 Created), a validation error with details per field (often400or422), or a server error (500). See HTTP status codesHTTP status codeA three-digit number in every server response: 200 means OK, 404 not found, 500 server error.Open in glossary →. - The app shows the result. A success screen or confirmation, or the errors next to the right fields, with everything the user typed still there.
Client-side vs server-side validation
In the app or browser
Client-side validation
- Instant feedback while the user fills in the form
- Required fields, formats, lengths, "passwords match"
- Saves a trip to the server for obvious mistakes
- Can be skipped, changed or simply missing
On the server
Server-side validation
- The same rules again, every time
- Things only the server knows: "email already registered", stock, prices, rate limits
- Rejects bad data with a clear error (often a 400 or 422)
- The only check you can trust
Ways to reach the server without the app's checks
- Calling the API directly with Postman or curl
- Editing the request in a proxy tool or DevTools
- An old app version with older (or no) rules
- A second client: website, iOS and Android each with their own checks
Client-side validation is a convenience for the user. Server-side validation is protection for the business. A developer can forget to add a rule to the app, the iOS and Android apps can have different rules, an old app version can have no rules at all, and anyone can send a request with a tool like Postman or change it on the way with a proxy toolProxy toolA program that sits between the app and the server so you can watch and change network traffic.Open in glossary →. Only the server sees every request.
| Rule | Client-side | Server-side |
|---|---|---|
| Required fields, formats, lengths | Yes, for quick feedback | Yes, always again |
| “This email is already registered” | No (only the server knows) | Yes |
| Price, discount, stock | Display only | Yes, the server decides |
| Too many attempts from one device | No | Yes (rate limitingRate limitingCapping how many requests a user or device can make in a period of time.Open in glossary →) |
Anatomy of a good form
Where should we deliver?
All fields are required unless marked (optional).
Delivery address
Postcode
For example SW1A 1AA
Enter a full postcode, like SW1A 1AA
Mobile number
Note for the courier (optional)
- 1
Clear title and note. Says what the form is for and how required and optional fields are marked.
- 2
Group with a heading. Related fields sit together under a heading and screen readers announce the heading.
- 3
Visible label. Above the field and always visible. A placeholder is not a label.
- 4
Help text before typing. Format and rules up front ("For example 27 3 1995"), not only after a mistake.
- 5
Right input type. type and inputmode open the right keyboard: email, phone pad, numbers.
- 6
Autocomplete token. autocomplete="postal-code" lets AutoFill and password managers fill the right value.
- 7
Error next to the field. Red border plus text and an icon, saying how to fix it. Never color alone.
- 8
Optional marked as optional. Usually fewer fields are optional, so mark those instead of every required one.
- 9
Specific button text. "Create account" says what happens. "Submit" or "OK" does not.
Labels, placeholders and help text
The label says what to enter; help text says how. Both stay visible while the user types. A placeholder is at most an extra example, because it vanishes on the first keystroke and often has low contrast (more on the Text Field page). Put formats and rules before the field (“At least 8 characters”, “For example 27 3 1995”): users shouldn’t have to fail once to learn the rules.
Required and optional
Pick one convention and use it everywhere. Most forms have fewer optional fields, so many teams mark those with “(optional)” and say so at the top. If the team uses an asterisk (*) for required fields instead, it must be explained (”* required”) and announced by screen readers, not just a red star. Test that what’s marked required is what’s actually required: a field marked optional that blocks submit, or a “required” field the server happily accepts empty, is a bug.
Grouping and order
Related fields belong together under a heading: “About you”, “Delivery address”, “Payment”. Screen readers should announce the group’s heading when you enter it. The order should match how people think (name before address, street before city), and the keyboard’s Next or Tab key should follow the same order (focus orderFocus orderThe order in which the Tab key moves through interactive elements.Open in glossary →). One column is easier to scan than two, especially on phones.
Input types and mobile keyboards
The field type decides which keyboard appears on a phone:
| Field | Web | What appears on a phone |
|---|---|---|
type="email" | Keyboard with @ and . | |
| Phone | type="tel" | Phone pad with + |
| Whole numbers (PIN, code) | inputmode="numeric" | Number pad |
| Amounts, weights | inputmode="decimal" | Number pad with . or , (depends on the region) |
| Web address | type="url" | Keyboard with / and .com |
A keyboard is only a hint: people paste, use hardware keyboards and autofill, so a “numbers only” field still needs validation. The Text Field page has a live keyboard demo.
Autocomplete and autofill
Browsers, iOS, Android and password managersPassword managerA tool that stores credentials and fills them into login forms, like Apple Passwords, Google Password Manager or 1Password.Open in glossary → can fill a whole form in one tap, but only if each field says what it contains. On the web that’s the autocomplete attribute: name, email, tel, street-address, address-level2 (city), postal-code, country, bday, new-password, one-time-code and more. The Text Field page has a table of the most common hints.
Dev note: Names in code
Groups on the web are a <fieldset> with a <legend>. The keyboard is set with type and inputmode on the web, keyboardType on iOS and inputType on Android. Autofill hints are autocomplete on the web, textContentType on iOS and autofillHints on Android. Error messages are linked to fields with aria-invalid="true" and aria-describedby.
What to test:
- AutoFill puts each value in the right field. A wrong token is easy to miss in code review: the city lands in the postcode, the surname in the first name.
- Autofilled values pass validation. Autofill can add a country code, a trailing space or a format your rules don’t expect.
- The form notices the values. Some forms only react to typing, so autofilled fields still count as “empty” or the button stays disabled.
- Sign up offers a strong password and the new password is saved to the password manager afterwards (
autocomplete="new-password"). - Fields about the user have tokens. On the web this is a WCAG requirement: 1.3.5 Identify Input Purpose (AA).
When to validate
There are three moments to check a field. Each has trade-offs (try them live on the Text Field page):
| Timing | Good for | Problem |
|---|---|---|
| On submit | Short forms; simple to build | Users discover all problems at the end |
| On blur (when leaving the field) | Most fields; the usual best default | Can fire too early if the user just taps around |
| While typing | Password rules checklist, character counters, “username available” | Shouts at people before they’ve finished |
Whatever the team chooses, test that it’s consistent across the form, that errors clear as soon as the value is fixed, that tapping into an empty field and out again doesn’t immediately paint everything red, and that submit always validates everything, including fields the user never touched.
Error messages that help
Vague, at the top, input wiped
Date of birth
Postcode
A code instead of an explanation, red borders with no text, and the postcode the user typed is gone. Which field is wrong, and how do you fix it?
Specific, next to the field, input kept
There are 2 problems
- Enter a date of birth like 27 3 1995
- Enter a full postcode, like SW1A 1AA
Date of birth
Enter a date of birth like 27 3 1995 (February has no 31st)
Postcode
Enter a full postcode, like SW1A 1AA
A summary at the top, a message under each field that says how to fix it, and the user’s input is still there.
A good error message:
- Is specific and tells the user what to do. “Enter a postcode like SW1A 1AA”, not “Invalid input” or “Error 422”. (WCAG 3.3.3 Error Suggestion, AA.)
- Sits next to the field it’s about, and the field is visually marked.
- Uses plain language. No codes, no blame (“You entered an illegal value”), no jargon (“Regex mismatch”).
- Isn’t color only. Red plus text plus an icon, so people who can’t see red still notice it. (WCAG 1.4.1 Use of Color, A, and 3.3.1 Error Identification, A.)
- Reaches screen reader users. The field is announced as invalid and the message is read out with it. After a failed submit, focus moves to the first invalid field or to an error summaryError summaryA box at the top of a form listing every problem after a failed submit, each linking to its field.Open in glossary → at the top that lists every problem as a link. Each link must move focus to its field.
- Keeps the user’s input. Nothing typed is cleared after an error. Many teams clear the password on purpose; if so, say so and keep everything else.
- Disappears when the problem is fixed, and comes back if it’s broken again.
Server errors need the same care. “Something went wrong” with no next step is a dead end. Better: “We couldn’t create your account right now. Your details are saved, please try again in a minute.” And if the server rejects one field (“This email is already registered”), the message belongs next to that field, not in a generic toast.
Data formats and edge cases
Most “invalid input” bugs are really valid input the developer didn’t expect. Keep these lists handy as test dataTest dataThe input values, accounts and records you use while testing.Open in glossary →.
Names
| Try | Why |
|---|---|
O'Brien, D'Angelo | Apostrophes are part of many surnames |
Đorđe Petrović, Zoë, José, Łukasz | Letters with diacriticsDiacriticsAccent marks on letters, like é, ü, č or ž. Search usually should ignore them.Open in glossary → must be accepted and displayed correctly later |
Anne-Marie, García Márquez, van der Berg | Hyphens, two surnames, lowercase particles |
Sukarno (one name) | Many people have a single name. “First name” and “Last name” both required blocks them |
| A 70-character name | Long names exist. Check the limit, the error, and every screen and email that shows the name |
王芳, Јована | Other scripts, if the product supports those markets |
Two separate fields for first and last name don’t fit every culture. A single Full name field is often simpler. If the spec splits them, test what happens to single names and long double surnames.
Emails
- Plus addressingPlus addressingAdding +something before the @ in an email address, like anna+shop@mail.com. Mail still reaches anna@mail.com.Open in glossary →:
anna+groceries@mail.comis valid and widely used to filter mail. Rejecting+is one of the most common form bugs. - Subdomains and long domains:
anna@mail.example.co.uk,anna@company.photography. - Dots and dashes:
anna.maria-k@mail.com. - Length: the part before
@can have up to 64 characters, and a whole address up to 254 in practice. Test a long but valid one. - Case and spaces:
Anna@Mail.comand a trailing space from autofill should be cleaned up, not rejected. - Typos:
anna@gmial.comis valid but wrong. Some apps suggest “Did you mean gmail.com?”. Nice to have, not a validation rule.
Phone numbers
People type phone numbers the way they see them: +44 7700 900123, +385 (91) 234-5678, 0049 151 1234567. The international format (E.164) has up to 15 digits after the +. A good form accepts spaces, dashes and brackets, removes them before saving, and either asks for the country or offers a country code picker. Test with numbers from every market the product serves, and never rely on a 10-digit limit.
Postcodes by country
| Country | Example | Format |
|---|---|---|
| United States | 94103, 94103-1234 | 5 digits, optional ZIP+4 |
| United Kingdom | SW1A 1AA, M1 1AE | Letters and digits, with a space, different lengths |
| Netherlands | 1012 AB | 4 digits, space, 2 letters |
| Canada | K1A 0B6 | Letter-digit-letter, space, digit-letter-digit |
| Germany, Croatia | 10115, 10000 | 5 digits (a leading 0 is possible in Germany: 01067) |
| Hong Kong | none | No postcodes at all: the field must be optional there |
The postcode rule must depend on the selected country, and changing the country should re-check the postcode. A leading zero (01067) is a classic: if the field is stored as a number, it becomes 1067.
Dates and ages
- The birthday boundary: with an 18+ rule, someone whose 18th birthday is today is allowed. Test the day before, the day itself and the day after. This is boundary value analysisBoundary value analysisTesting values at and just around the edges of valid ranges, where bugs love to hide.Open in glossary →, and the classic bug here is an off-by-one errorOff-by-one errorA bug where a count or boundary is wrong by exactly one, like counting days instead of nights.Open in glossary →.
- 29 February: when does someone born on 29 February 2008 turn 18 in a non-leap year? The answer depends on the country’s law. Ask, then test it.
- Impossible dates:
31 2 1995should be rejected with a message, not silently become 3 March (see Date Picker). - Day and month order:
03/04/2005is 3 April in Europe and March 4 in the US. Separate Day, Month and Year boxes, or a date picker, avoid the confusion. - Future and unrealistic dates: born in 2090 or in 1850.
Numbers, decimals and amounts
1,5 is one and a half in Germany, Croatia and much of Europe; 1.5 in the US and UK. In an amount field, 1,500 can mean fifteen hundred or one and a half. Test with the device set to different regions (see Localization and RTL), and check that 0, negative numbers, very large numbers and leading zeros are handled as the spec says.
Spaces, paste, emoji and formatted text
- Leading and trailing spaces should be trimmed before validating and saving. Spaces inside a password are part of it and must be kept.
- Spaces only in a required field should count as empty.
- Paste must work everywhere, including password and “confirm” fields. Paste a value with a line break at the end (it happens when copying from emails and PDFs).
- Formatted text from Word, a PDF or a website can bring curly quotes (
’instead of'), non-breaking spaces and invisible characters.O’Brienwith a curly apostrophe must work too. - Emoji in names, notes and addresses: accepted or rejected with a clear message, never stored as
???. - Length limits on paste: if a field has a maximum, pasting a longer value shouldn’t cut it silently (see truncationTruncationText that gets cut off because it doesn't fit its space.Open in glossary →).
Multi-step forms, double submit and server errors
Multi-step forms and saving progress
Long forms (insurance quotes, loan applications, checkouts) are often split into steps, a wizardWizardA long task split into ordered steps with a progress indicator, like a checkout.Open in glossary →. Test that Back keeps what was entered, that you can’t skip a required step, that the step indicator is right, and that a draft survives a refresh or a closed app if the spec promises it. The Wizard page has a full bug hunt on this. For long forms, ask whether progress is saved on the server or only on this device: a draft that exists only on the phone is gone when the user switches to the laptop.
Preventing double submit
A slow network, an impatient user, and a button that stays active: that’s a double submitDouble submitA bug where an action runs twice because the user tapped or clicked twice quickly.Open in glossary →, and it creates two accounts, two bookings or two support tickets. The fix has two layers. The app disables the button and shows a loading state as soon as it’s pressed (and pressing Enter again must not send another request either). The server recognizes a repeated request, for example with an idempotency key (see idempotencyIdempotencyAn action that gives the same result no matter how many times it is repeated.Open in glossary →). Test with the network throttled: tap twice, press Enter twice, tap and press Enter.
Server errors and lost connections
What happens when the server answers 500, or the connection drops after you tap Submit? The user should see a clear message, all their input should still be there, and they should be able to try again without creating a duplicate. Test it by turning on airplane mode right after submitting, or with a proxy tool that returns an error. On the web, a broken form that wipes everything after an error is one of the most frustrating bugs a user can meet.
Session timeout during a long form
Users fill in long forms slowly: they look up their passport number, answer the door, come back an hour later. If the sessionSessionThe period during which a user stays logged in without entering their credentials again.Open in glossary → expired meanwhile, the submit fails. Good behavior: warn before the session ends and let the user extend it (WCAG 2.2.1 Timing Adjustable, A), or after logging in again, return to the form with the data still there. Bad behavior: a login screen, and then an empty form. Test it by leaving a filled form open past the timeout, or ask a developer for a build with a 1-minute timeout.
The browser Back button and refresh
- Back after submit: going back to a submitted payment or sign up form and submitting again must not create a second order or account.
- Refresh on the result page: if the result page was the direct answer to a
POST, the browser asks “Confirm form resubmission”. Good sites redirect after a successful submit, so a refresh is harmless. - Back from the next page to fix something: the form should still be filled in, not empty.
Security and privacy basics
- No personal or secret data in URLs. A form sent with
GETputs every field in the address as query parametersQuery parameterData in a URL after the ?, like ?q=mug&sort=price, often used to keep search and filter state.Open in glossary → (?email=…&phone=…). URLs end up in browser history, server logs, analytics and shared links. Check the Network tab in DevToolsDevToolsDeveloper tools built into browsers for inspecting pages, network traffic and errors.Open in glossary →: forms with personal data should usePOST. - Password fields are masked, have show/hide, allow paste and work with password managers. Details on the Password Field page.
- Rate limiting on sign up. Without it, a script can create thousands of fake accounts or flood people’s inboxes with confirmation emails. Check for rate limitingRate limitingCapping how many requests a user or device can make in a period of time.Open in glossary →, a CAPTCHA or email verification, and that the limit is enforced on the server.
- Consent is opt-in. Marketing checkboxes start unticked (required under GDPR in the EU), and the Terms checkbox is actually enforced, on the server too. See Checkbox.
- Input is stored as text, not run as code. Try
<b>Anna</b>in a name and check every place it’s shown later (see Security basics). - Only collect what’s needed. A newsletter sign up that asks for a date of birth and phone number is a privacy question worth raising.
Accessibility checklist for forms
Forms are where accessibility problems hurt most: if someone can’t submit, they can’t buy, book or sign up at all. Use this list together with Accessibility basics:
Form accessibility checklist
0 of 13 checked
On mobile, run the same checks with VoiceOver and TalkBack (screen readersScreen readerSoftware that reads the screen aloud for blind and low-vision users, like VoiceOver or TalkBack.Open in glossary →): every field should announce its label, type, value, hint and error.
What usually goes wrong
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Valid data rejected | O'Brien, Đorđe, anna+shop@mail.com or +44 7700 900123 gets “invalid” | High |
| 2 | One country’s format for all | UK or Dutch postcodes rejected, US phone format required everywhere | High |
| 3 | Client-only rules | The app blocks bad data, but the API accepts it | Medium–High |
| 4 | Shouting while typing | “Invalid email” after the first letter | Low–Medium |
| 5 | Errors by color only | Red border, no text, nothing for screen readers | Medium–High |
| 6 | Vague or misplaced errors | “Error 422” in a toast; the field isn’t marked | Medium |
| 7 | Input lost | A server error, timeout or Back clears the form | High |
| 8 | Double submit | Two accounts or two tickets after a slow response | Medium–High |
| 9 | Boundary bugs | 18-year-olds rejected on their birthday, limits off by one | Medium |
| 10 | Broken autofill | Values land in the wrong fields, or the form ignores them | Medium |
| 11 | Focus not managed | After submit, nothing tells a screen reader user what’s wrong | High (for affected users) |
| 12 | Sensitive data in the URL | ?email=…&dob=… visible in the address bar and logs | High (privacy) |
Example requirements
Here’s the spec for the form in the bug hunt below: a sign up form for Larder, a grocery delivery app that also sells beer and wine.
Find the bug
Larder’s sign up form below has ten bugs. The phone has an AutoFill bar at the bottom, and under it you can choose what the server answers to the next submit and watch the network log. Explore like a tester:
- Type slowly and watch when errors appear.
- Use real-world data: names, emails and phone numbers from the lists above, and a UK postcode.
- Fill the form with AutoFill and look at every field.
- Try dates of birth around the 18th birthday. Today in the demo is 14 May 2026.
- Submit with mistakes, then use the error summary.
- Make the server fail and submit a valid form.
🐞 Bug hunt: Larder sign up
This demo has 10 hidden bugs. Explore it like a tester, then check your findings.
Create your account
All fields are required unless marked (optional).
Next server response
Today in this demo: Thursday, 14 May 2026
Network log
Submit the form to see the request…
- 1
Hint: Type your email slowly, one letter at a time.
- 2
Hint: Sign up with an email like maya+food@mail.com.
- 3
Hint: Try O'Brien, Đorđe Petrović or Zoë.
- 4
Hint: Type the phone number exactly like the example under the label.
- 5
Hint: Choose United Kingdom or Netherlands and enter a real postcode.
- 6
Hint: Tap the AutoFill bar and read every filled field.
- 7
Hint: Today is 14 May 2026. Try someone born on 14 May 2008, then on 13 May 2008.
- 8
Hint: Leave the date of birth empty, or enter 31 2 1995, and submit.
- 9
Hint: Submit the empty form, then tap a problem in the red summary box.
- 10
Hint: Set the next server response to 500 and submit a valid form.
How to test a registration form
“How would you test a registration form?” is one of the most common interview tasks, and one of the most common real tasks too. Here’s a structure that works for both:
- Ask questions first. Which fields are required? What are the rules for each (length, format, allowed characters)? Which countries and languages? What happens after sign up: a confirmation email, auto login? What if the email is already registered? These questions alone often reveal gaps in the acceptance criteriaAcceptance criteriaConditions a user story must meet to be considered done and accepted.Open in glossary →.
- Run the happy path end to end. Sign up with valid data, open the confirmation email, log in with the new account and check that every value was saved correctly (on the profile, in emails, in the admin panel or database).
- Test each field. Empty, spaces only, valid and invalid classes (equivalence partitioningEquivalence partitioningSplitting inputs into groups that should behave the same, then testing one value from each group.Open in glossary →), minimum, maximum and one beyond (boundary value analysisBoundary value analysisTesting values at and just around the edges of valid ranges, where bugs love to hide.Open in glossary →).
- Use real-world data. Names with apostrophes and accents, plus addresses, international phone numbers, postcodes from each supported country, the 18th birthday, pasted text.
- Check validation behavior. When errors appear, what they say, whether they clear, the error summary, where focus goes, and that nothing typed is lost.
- Test the whole form. Double submit, duplicate email, server error, no connection, session timeout, Back and refresh, closing the app halfway.
- Go around the app. Send the same request with invalid data straight to the API (Postman or DevTools) to prove the server validates too.
- Check security and privacy. No data in the URL, password masked, rate limiting, marketing opt-in unticked, Terms enforced, no account enumeration.
- Check accessibility. Screen reader, keyboard only, large text, contrast, autocomplete tokens.
- Repeat on each platform. Keyboards and AutoFill on iOS and Android, browsers and password managers on the web, small screens and dark mode.
Test scenarios
Functional
- Sign up with all valid data; the account is created and every value is saved exactly as entered (after trimming).
- Optional fields can be left empty; required fields can’t.
- The confirmation email arrives, and the new account can log in.
- Changing the country updates the postcode rules and re-checks the postcode.
- AutoFill and password managers fill every field correctly.
Negative
- Submit the empty form: every required field gets a message and the summary lists them all.
- Spaces only in required fields.
- Invalid formats:
anna@,anna@@mail.com,12abcas a phone number,SW1Aas a UK postcode. - Underage date of birth, impossible date (
31 2 1995), a date in the future. - Email already registered (the message follows the spec and doesn’t reveal more than intended).
- Terms not accepted.
Edge cases
- Names:
O'Brien,O’Brien(curly apostrophe),Đorđe,Anne-Marie, a single name, 100 and 101 characters. - Emails: plus address, subdomain, 64-character local part, uppercase.
- Phone: with spaces, dashes and brackets, with
00instead of+. - Postcodes for every supported country, including a leading zero.
- Date of birth: exactly 18 today, 18 tomorrow, 29 February.
- Pasting values with a trailing line break or non-breaking space; emoji in the street name.
- Decimal comma vs point in numeric fields, with the device set to a different region.
Whole-form behavior
- Double tap and double Enter on submit with a slow network: one account.
- Server returns
500,422or times out: clear message, input kept, retry works. - Connection lost right after submitting.
- Session expires while the form is open.
- Back after a successful submit, refresh on the result page, Back to fix a value.
- App sent to the background and reopened halfway (see Background and foreground).
Server-side
- Send the request without the app, with each client rule broken: too long, wrong format, missing required field, extra unknown fields.
- Check that the server trims and normalizes values the same way the app does.
- Many sign ups from one device or IP: rate limit or CAPTCHA kicks in.
UI and accessibility
- Labels, help text, optional markers and grouping are consistent.
- The right keyboard opens for each field on iOS and Android.
- The focused field and its error are not hidden behind the keyboard.
- Everything from the accessibility checklist above.
Example test cases
TC-FORM-001Sign up with valid data saves every valuepositivehigh
Steps
- Open Create account
- Fill in every field with valid data
- Tap "Create account"
- Open the profile and the confirmation email
Test data
Full name: Đorđe O'Brien-Petrović / email: djordje+food@mail.com / phone: +44 7700 900123 / UK, SW1A 1AA
Expected result
The account is created. The name, email, phone and address appear exactly as entered (trimmed) on the profile and in the email.
TC-FORM-002Postcode rules follow the selected countrypositivehigh
Steps
- Choose United Kingdom and enter "SW1A 1AA"
- Change the country to Netherlands
- Enter "1012 AB"
- Change the country to Germany and enter "01067"
Expected result
Each postcode is accepted for its country. After changing the country, the old postcode is re-checked. "01067" is saved with its leading zero.
TC-FORM-003Age boundary on the 18th birthdayedgehigh
Preconditions
- Device date is 14 May 2026
Steps
- Enter date of birth 15 5 2008 and submit
- Change it to 14 5 2008 and submit
- Change it to 13 5 2008 and submit
Expected result
15 May 2008: "You must be 18 or older". 14 May 2008 and 13 May 2008: the account is created.
TC-FORM-004Errors are not shown while the user is typingnegativemedium
Steps
- Tap into Email
- Type "anna" slowly
- Leave the field
- Go back and complete it to "anna@mail.com"
Expected result
No error while typing in step 2. After leaving the field, an error with a text message appears. It disappears as soon as the value is valid in step 4.
TC-FORM-005Error summary moves focus to each fieldnegativemedium
Steps
- Submit the empty form
- Check where focus is
- Activate the first link in the error summary
- Repeat with keyboard only (Tab, Enter) and with a screen reader
Expected result
Focus moves to the summary after submit. Each link moves focus to its field, which is scrolled into view and announced with its error.
TC-FORM-006Input is kept after a server errornegativehigh
Preconditions
- The sign up endpoint returns 500 (proxy tool or test switch)
Steps
- Fill in all fields with valid data
- Tap "Create account"
- Read the message
- Switch the server back to normal and tap "Create account" again
Expected result
A clear message says the account could not be created and to try again. All fields keep their values (the password may be cleared if the spec says so). The second try creates exactly one account.
TC-FORM-007Double submit creates one accountedgehigh
Preconditions
- Network throttled to "3G" in DevTools or a slow profile in a proxy tool
Steps
- Fill in valid data
- Tap "Create account" twice quickly
- Press Enter while the request is in progress
Expected result
The button is disabled and shows a loading state after the first tap. One request is sent and one account exists.
TC-FORM-008Server rejects invalid data sent without the appnegativehigh
Preconditions
- Postman or DevTools "Edit and resend" is available
Steps
- Capture a valid sign up request
- Change the date of birth to make the user 16
- Remove acceptedTerms
- Send the request
Expected result
The server answers with a validation error (for example 422) naming the fields. No account is created.
TC-FORM-009AutoFill fills every field correctlypositivemedium
Preconditions
- A saved contact with full address exists on the device or in the browser
Steps
- Focus the Full name field
- Choose the saved contact from AutoFill
- Read every field
- Submit
Expected result
Every value lands in the matching field (city in city, postcode in postcode). Autofilled values pass validation and the form submits.
Tip: click a test case to expand it.
Mobile vs web
- Keyboards: check the keyboard type, auto-capitalization (on for names, off for emails) and autocorrect (off for names, emails and codes) on each field, with Gboard and Samsung Keyboard on Android.
- AutoFill: iOS offers contacts and passwords above the keyboard, Android uses its Autofill service. Test that values land in the right fields and that “Use strong password” works on sign up.
- The keyboard covers things: the focused field, its error message and the submit button must not hide behind the keyboard. Scroll the form with the keyboard open.
- Next and Done keys: Next should move to the next field in order; the last field’s Done or Go should submit or close the keyboard.
- Interruptions: a phone call, switching apps to copy a code, or the app being killed in the background should not lose what was typed (see Interruptions).
- Native pickers: dates, countries and times often use system pickers. Test them with large text and VoiceOver or TalkBack.
- Old app versions: users don’t all update. A rule added to the new app version must also exist on the server, or old versions keep sending bad data.
- Browser autofill and password managers: Chrome, Safari, Firefox and tools like 1Password should detect every field. In DevTools, check each field’s
autocomplete,type,inputmodeandname. - Built-in browser validation:
requiredandtype="email"show the browser’s own bubbles, which look different in every browser and can’t always be read well. Many teams turn them off and show their own messages. Know which one your app uses. - Keyboard only: Tab through the whole form, select with arrows and Space, submit with Enter. Check the focus ring and that Enter doesn’t submit twice.
- Network tab: check that the form uses
POST, that no personal data appears in the URL, and what an error response contains. - Back, refresh and multiple tabs: go back after submitting, refresh the result page, open the form in two tabs.
- Mobile browsers: the right keyboard depends on
typeandinputmode. Test on a real phone, not only in a resized desktop window. - Zoom and reflow: at 200% zoom and at 320 px wide, labels, errors and buttons must stay visible and in order.
Checklist
Forms and validation checklist
0 of 14 checked
Check your understanding
Quick quiz
0/6 answered · 0 correct
1.The app blocks names longer than 50 characters. Why should you still test a 300-character name?
2.An email field shows "Invalid email" as soon as you type the first letter. What is the best description of the problem?
3.Which of these is a valid email address that forms often reject by mistake?
4.The spec says "18 or older". Today is 14 May 2026. Which date of birth is the most important boundary to test?
5.After a 500 error, the sign up form shows "Something went wrong" and all fields are empty. What should you report?
6.Which error message is best for a UK postcode field containing "SW1A"?
Key takeaways
- A good form has visible labels, rules before typing, clear grouping, the right keyboards and autocomplete tokens.
- Client-side validation is a convenience, server-side validation is protection. Test both, and go around the app to prove the server checks.
- Validate on blur or submit, not while the user is still typing, and clear errors as soon as they’re fixed.
- Errors must be specific, next to the field, not color only, announced to screen readers, and must never wipe the user’s input.
- Test with real-world data: apostrophes and accents, plus addresses, international phone numbers, postcodes per country, the 18th birthday, spaces, paste and emoji.
- Test the whole form: double submit, server errors, timeouts, Back and refresh, security and accessibility.
Finished this page?Nice work, this page is complete!
Mark it as done to track your progress. It's saved in this browser, no account needed.
Its review cards are now in Bites ⚡