CSE 134B Web Client Languages
  1. Interaction
  2. Forms
  3. Forms for People

Interaction · Forms 06

Forms for People

Every field in a form asks a person to spend time and to hand over something about themselves. This page is about the questions that sit between the markup and the world: what to ask at all, how to ask it of people who do not share your name order, address format or decimal point, what the law says about the answers, and what happens to the data after the button is pressed.

The earlier pages in this section built forms that are correct: every control named and labeled, every group legible, every message in its place, every constraint a service to the person and none of them mistaken for security. A form can be all of that and still fail the people it is for. It can ask fifteen questions where four would do. It can refuse a real postal code because it is not five digits, split a name that does not split, read a German customer's 1234,56 as more than a hundred thousand, and quietly send what someone typed to an analytics company before they decide to submit. This page takes up those failures, one intersection at a time, and ends by pointing at what JavaScript adds once the HTML is right.

1. Collect less

The cheapest field to build, to validate, to secure, to store, to explain in a privacy notice and to delete later is the one that is not there. Every field costs the person filling in the form some effort and some exposure, and costs the organization that keeps the answer some risk. The first design question for any form is not how to lay out the fields but which ones should exist.

Every field earns its place

Before a field goes into a form, it should have answers to four questions:

  • What is it for? A specific use, now: "to ship the order," "to send the receipt." "Marketing might want it" and "we have always asked" are not uses.
  • Who will use it? If nobody in the organization can name the person or system that reads the answer, nobody will, and the data just sits there waiting to leak.
  • Could we get it another way? Some answers can be derived or looked up instead of asked for, as the next part shows.
  • What happens if it is empty? If the service works without it, it is optional at most, and probably should be asked later, when it is needed, or not at all.

Run a typical sign-up form through those questions and it shrinks. A title (Mr, Ms, Dr) is rarely used for anything. A second email box, "confirm your email," doubles the typing to catch a typo that a confirmation message catches better. A date of birth is often asked when the only question that matters is whether the person is old enough. A phone number on a newsletter sign-up has no use at all. A postal address on an account that will never ship anything is a liability with a label on it.

Required, optional, and absent

A field that survives the questions is either required, because the service cannot work without it, or optional, because it improves the service for people who choose to give it. Mark the difference in the label, as Organizing Forms describes, and put required only on the fields that really are. An optional field should also say what it improves: "Phone (optional): only used if the courier cannot find you." People are far more willing to give something when they can see what it buys them, and far less willing when a form demands it without a reason.

Be wary of optional as a compromise. A field that nobody can justify as required is often a field nobody needs, and keeping it as optional still lengthens the form, still invites some people to fill it in, and still leaves the organization holding the answers. When in doubt, leave it out; a field can be added later, when someone shows the need.

Do not ask what you can derive

Some answers follow from others, or can be looked up:

  • The card brand follows from the first digits of the card number. A "Visa or Mastercard?" radio group asks a question the number already answers.
  • A city can often be suggested from a postal code in countries where codes are fine-grained, though the person must be able to correct it, because codes and towns do not map one to one.
  • Eligibility is usually a yes-or-no question. "Are you 18 or older?" asks less than a full date of birth, and stores less.
  • What the browser already knows, it can offer. The autocomplete tokens from Form Accessibility and Usability let the browser fill a name, an email, an address and a card in one tap, from data the person chose to save.

Deriving has a limit. Do not infer something personal and then act on it silently: a language guessed from an IP address, a country guessed from a browser setting, a gender guessed from a name. A guess can be offered as a default, visibly, with a way to change it; it must never replace the person's own answer.

Length, steps, and the cost of giving up

A long form is not only slower; it is a form more people never finish. The best public figures come from the Baymard Institute, which has studied checkout usability for well over a decade. Its page of cart abandonment statistics, last updated 22 September 2025, reports an "average documented online shopping cart abandonment rate" of 70.22%, calculated from 50 different studies. Most of that is people who were only browsing, but not all. In Baymard's own survey of the reasons, "17% of US online shoppers have abandoned an order due to a 'too long / complicated checkout process'," and 18% gave the reason that the site wanted them to create an account.

Baymard also counts fields. The same page reports that "the average US checkout flow contains 23.48 form elements displayed to users by default," and that for most sites "it's possible to make a 20-60% reduction in the number of form elements." Its estimate of an ideal checkout is 12 to 14 form elements, or 7 to 8 if only fields are counted. The lesson is not a magic number. It is that most forms carry fields that do not earn their place, and that those fields cost real people real time, and cost the site real customers.

Splitting a long form into steps can make it feel lighter, as Organizing Forms explains, but steps are a way to present the fields, not a way to justify them. Shorten first; then organize what remains. And never require an account to finish a task that does not need one: offer a guest path, and offer to create the account afterward, when the person has already seen what it is for.

2. People are not one format

Most form bugs that hurt people are not code errors. They are assumptions: that everyone has a first name and a last name, that every address has a state and a five-digit ZIP code, that a phone number has ten digits, that 03/04 means March. Each assumption works for the people who wrote the form and fails for someone else. The fix is usually to ask less precisely, accept more, and let the server do any splitting it truly needs.

Names

Names vary more than any other common field. Some people have one name only. In Chinese, Japanese, Korean and Hungarian names the family name usually comes first; in much of the Spanish-speaking world people carry two family names; Icelandic names are mostly patronymics, not family names at all. Names contain spaces, hyphens, apostrophes and accents, as the old deck's Joe O'Reilly reminded us, and are written in every script there is. The W3C's internationalization article Personal names around the world collects many more cases, and they all point the same way.

Ask for the name in one field, labeled "Full name," and accept whatever is typed. If the service needs to address the person in an email, ask separately, and optionally, "What should we call you?" rather than guessing which part of the name is the friendly one. Split fields with the given-name and family-name autocomplete tokens are for cases where an outside system demands them, such as matching a passport for a flight booking, and even then the labels should say what is meant, not "First" and "Last."

<form-field> <label for="full-name">Full name</label><br> <input id="full-name" name="full-name" type="text" required autocomplete="name" spellcheck="false"><br> </form-field> <form-field> <label for="call-me">What should we call you? (optional)</label><br> <input id="call-me" name="call-me" type="text" autocomplete="nickname" spellcheck="false" aria-describedby="call-me-hint"><br> <output id="call-me-hint" class="hint" for="call-me">Used to greet you in emails.</output><br> </form-field>

Never put a pattern such as [A-Za-z ]+ on a name. It rejects Zoë, José, O'Brien and every name written in a script other than Latin, and it protects nothing, because a name is just text for the server to store and encode safely. The same goes for minimum lengths: Ng and Li are complete family names.

Addresses

An address has no universal shape. The United States has states and five-digit ZIP codes, with an optional four more. The United Kingdom has no states in its postal addresses and postcodes made of letters and digits, such as SW1A 1AA. Canada's postal codes alternate letters and digits. Japanese addresses run from the largest unit to the smallest and are often written with the postal code first. Ireland had no national postcode system until Eircode arrived in 2015, and Hong Kong still uses none. A form with a required "State" select of fifty options and a pattern="[0-9]{5}" ZIP code is a form for one country.

Four addresses, four shapesFour boxes, each holding an address from one place. United States: a street line, then San Diego, CA 92101, with a state and a five-digit ZIP code. United Kingdom: a street, the town Leeds, and the postcode LS1 6AB, letters and digits, with no state. Japan: the postal code 100-0001 written first, then the prefecture and ward, then the block number, largest unit first. Hong Kong: a flat and building, then the district Kowloon, and no postal code at all. A note below says a form with a required state and a five-digit pattern fits only the first box.United States123 Palm AveSan Diego, CA92101state: requiredZIP: 5 digitsUnited Kingdom10 Market StLeedsLS1 6ABno statepostcode: lettersand digitsJapan100-0001Tokyo, Chiyoda-kuChiyoda 1-1prefecture, not state7 digits, writtenfirst, largest unitto smallestHong KongFlat 5A, Block 28 Hill RoadKowloonno postal codedistrict or regionrequired "State" + pattern="[0-9]{5}" fits only the first box
The same three or four lines carry different parts in a different order from one country to the next. Only the first box fits a form built for one country.

Three habits make an address form work for the world:

  • Country first. The country decides what the rest of the address looks like, so ask it first. With no script, the form shows general fields; with script, it can relabel and reshape them for the chosen country: "Postcode" or "ZIP code," a state, a province, a prefecture or nothing, and a format hint that fits. Open data such as Google's libaddressinput, the per-country formats behind Chrome's address autofill, records these shapes so nobody has to write them from memory.
  • General fields, loosely checked. Two address lines, a city or town, a region that may be empty, and a postal code that may be empty. A pattern on the postal code helps only when the form knows the country and the country has a fixed format, and even then it should allow spaces and either letter case.
  • The right tokens. country or country-name, address-line1 and address-line2, address-level2 for the city, address-level1 for the state or province, and postal-code. They are named for the parts, not for one country's words, so autofill works in every country.
<fieldset> <legend>Shipping address</legend> <form-field> <label for="country">Country or region</label><br> <select id="country" name="country" required autocomplete="shipping country"> <option value="US">United States</option> <option value="CA">Canada</option> <option value="GB">United Kingdom</option> … </select><br> </form-field> <form-field> <label for="line1">Street address</label><br> <input id="line1" name="line1" required autocomplete="shipping address-line1"><br> </form-field> <form-field> <label for="city">City or town</label><br> <input id="city" name="city" required autocomplete="shipping address-level2"><br> </form-field> <form-field> <label for="region">State, province or region (if any)</label><br> <input id="region" name="region" autocomplete="shipping address-level1"><br> </form-field> <form-field> <label for="postal">Postal code (if any)</label><br> <input id="postal" name="postal" autocomplete="shipping postal-code"><br> </form-field> </fieldset>

The postal code is a text field, never type="number": a number field drops the leading zero of a Boston ZIP code such as 02134, rejects every letter in a Canadian code, and offers a spinner to step a code up by one, which means nothing. That rule from Form Fields applies to every identifier made of digits.

Phone numbers

Phone numbers are just as varied. The international standard, ITU-T E.164, allows up to fifteen digits including a country code of one to three digits, and national numbers range from a handful of digits to a dozen. People write them with spaces, dashes, dots, parentheses and a leading plus sign, and none of that punctuation is wrong.

Use type="tel", which brings a phone keypad and, as Form Fields explains, does no validation of its own. Use autocomplete="tel", which fills the full international number with its country code. Accept the punctuation people type and let the server normalize the number. If the form serves more than one country, say so in the hint ("Include your country code if you are outside the US") or offer a separate country-code field with autocomplete="tel-country-code". A pattern of exactly ten digits rejects every international customer and many who type a space.

Dates

Written dates are ambiguous. In the United States 03/04/2026 is the fourth of March; in most of the world it is the third of April. Avoid free-text dates in a fixed order. A date picker, type="date", displays the date in the person's own format and always sends the unambiguous ISO form, 2026-04-03, so the ambiguity never reaches the server. For a date the person knows by heart, such as a birth date, scrolling a calendar back forty years is slow; three short labeled fields for day, month and year, with the tokens bday-day, bday-month and bday-year, are often faster, as the UK government's design system recommends for memorable dates. Before either, ask the first question again: does the service need the date at all, or only whether the person is old enough?

Gender and titles

Most forms that ask for gender do not need it. If yours does, for a medical service or a legally required report, say why in the hint, make sure you are asking the question you mean (sex recorded at birth, legal sex and gender identity are three different questions, and most services need none of them), and offer answers that fit everyone: options that include "Prefer not to say" and a way to describe oneself in a text field. Make the question optional unless the law requires an answer.

Titles are the same in miniature. A select of Mr, Mrs, Miss and Ms forces a choice about marital status that has no bearing on a sign-up, and leaves out Mx, Dr, Rev and everyone who uses no title. If the service writes formal letters, an optional free-text "Title" field covers everyone. Most services need no title field at all.

Language and direction

The lang attribute on <html> tells the browser and assistive technology what language the page is in; it chooses a screen reader's voice and pronunciation, the spell checker's dictionary and the hyphenation rules, and inputs inherit it. A field meant for text in another language, such as a message in Spanish on an English page, can carry its own lang.

Text in Arabic, Hebrew, Persian and Urdu runs right to left. A form must accept it and display it correctly even on a page whose own direction is left to right. Two attributes help. dir="auto" on an input or textarea lets the browser set the field's direction from the first strong character typed, so an Arabic comment lines up on the right while the person types it. And dirname tells the browser to send that direction along with the value, so the server can show the text in the right direction later:

<form-field> <label for="comment">Comment</label><br> <textarea id="comment" name="comment" dir="auto" dirname="comment.dir"></textarea><br> </form-field> comment=%D9%85%D8%B1%D8%AD%D8%A8%D8%A7&comment.dir=rtl

The browser adds a second entry to the entry list, named by the dirname value, holding ltr or rtl. The attribute works on <textarea> and on text-like inputs. It is Baseline widely available: MDN reports it has worked across browsers since August 2023, when Firefox 116 became the last engine to add it. The page's own text needs the same care; the course's CSS pages use logical properties such as margin-inline-start so a layout flips correctly when its direction does.

Finally, make sure the whole path from field to database carries every character. A page served as UTF-8 submits as UTF-8 by default, so accept-charset rarely needs setting, but a server or a database column that is not ready for UTF-8 can still turn Zoë into Zo? long after the form has done its part.

3. Money

Money is where a format mistake becomes a financial one. A form that misreads a number someone typed, or shows a price in a currency they assumed was their own, or lets the page decide the price, is a form that charges the wrong amount.

Separators change by locale

The same number is written differently across the world. These are the forms produced by the browser's own Intl.NumberFormat for the value one million, two hundred thirty-four thousand, five hundred sixty-seven and 89 hundredths:

LocaleWrittenDecimalGrouping
English (US), en-US1,234,567.89pointcomma, every three digits
German (Germany), de-DE1.234.567,89commapoint
French (France), fr-FR1 234 567,89commanarrow no-break space
German (Switzerland), de-CH1'234'567.89pointapostrophe
Hindi (India), hi-IN12,34,567.89pointcomma, then every two digits (lakh and crore)

So 1.234 is a little more than one in the United States and one thousand two hundred thirty-four in Germany. A person typing an amount types it the way they write it. A form that reads it the other way is wrong by a factor of a thousand, with no error to show for it.

A text field with a decimal keyboard

type="number" looks like the answer and is not, for amounts that people in many locales type. The HTML standard leaves its interface to the browser and encourages localization; it imagines a browser for the French market that would "display the value with apostrophes between thousands and commas before the decimals, and allow the user to enter a value in that manner, internally converting it to the submission format." Browsers differ in how far they go, and what they accept depends on the browser and its language settings, not on the person's habits or the page. In a test for this page, in October 2026, Chrome on a computer set to English took 1234,56 typed into a number field as the value 123456, with no error at all, while WebKit with a German locale read the same keystrokes as 1234.56. The submitted value, when there is one, is always a plain number with a point; when the browser cannot convert what was typed, the field is empty and its validity.badInput is true.

<label for="gift">Gift amount</label> <input id="gift" name="gift" type="number" step="0.01">

For a money amount, use a text field with inputmode="decimal". On a phone, the keyboard shows digits and the decimal separator for the person's locale, comma or point; the attribute is Baseline widely available and has worked across browsers since December 2021. It adds no validation and no conversion, so the form must say what it expects and the server must read the text deliberately, knowing which locale it was typed in:

<form-field> <label for="gift">Gift amount, in euros (EUR)</label><br> <input id="gift" name="gift" type="text" inputmode="decimal" autocomplete="transaction-amount" aria-describedby="gift-hint gift-error"><br> <output id="gift-hint" class="hint" for="gift">For example 25 or 25,50.</output><br> <output id="gift-error" class="error" for="gift" aria-live="polite"></output><br> </form-field>

The best confirmation is to read the amount back. A small script can parse what was typed using the locale's separators and show the result in the hint, "We read this as €1,234.56," so a misreading is caught by the person before it is charged. type="number" is still the right choice for counts, such as a quantity of 3 or a number of nights, where nobody types separators at all.

State the currency; never infer it

The dollar sign is used by the United States, Canada, Australia, Mexico, Hong Kong and many others. Intl.NumberFormat writes 1,234.50 Canadian dollars in Canadian English, and 1,234.50 Mexican pesos in Mexican Spanish, both as $1,234.50, exactly as it writes US dollars in US English. A price shown as "$24" to a visitor in Toronto is a question, not a price. Show the currency by its name or its three-letter ISO 4217 code wherever there is room for doubt: "24.00 USD," "Prices in US dollars."

Do not choose the currency silently from the visitor's IP address or browser language. Travelers, people on VPNs and people who simply prefer their own bank's currency are all misread that way. Offer a sensible default, show it plainly, and let the person change it. And do not assume two decimal places: the Japanese yen has no minor unit and the Kuwaiti dinar has three, which Intl.NumberFormat knows and a hardcoded step="0.01" does not.

const price = { amount: 2200, currency: 'EUR', minor: 2 }; // from the server, in cents const shown = new Intl.NumberFormat('de-DE', { style: 'currency', currency: price.currency }) .format(price.amount / 10 ** price.minor); // "22,00 €"

The server sets the price

Form Security showed a hidden price field changed to one cent in DevTools. The cure belongs here as well: a form sends what the person chose, the product, the quantity, the currency and the country, and never the price. The server looks the price up, adds the tax and shipping that apply to that country, converts currency if it must, and charges that. Anything the page displays, a total in an <output> or a converted price, is a preview the server recalculates.

What the page shows, what the form sends, what the server chargesThree boxes from left to right. The page shows: membership 22,00 euros, formatted for German. An arrow leads to what the form sends: plan equals annual, country equals DE, currency equals EUR, with no price; a crossed-out line notes that price equals 22.00 is never sent or trusted. An arrow leads to the server, which looks up the price for the annual plan in euros, 2200 cents, adds tax for Germany, and charges that amount. A dashed line back from the server to the page shows the server is where the displayed price came from in the first place.the page showsAnnual membership22,00 €formatted for de-DEa preview onlythe form sendsplan=annualcountry=DEcurrency=EURprice=22.00neverthe server chargesprice(annual, EUR)= 2200 cents+ tax for DEcharges what it computedthe displayed price came from the server in the first place
The page formats the price for the person; the form sends their choices; the server decides what they pay. Keep money in whole minor units, such as cents, on the server, so no floating-point rounding ever touches a charge.

What the page shows and what is charged must still agree, and when they cannot, the page must say so before the button is pressed. Baymard's list of abandonment reasons is led by extra costs: 40% of the US shoppers it surveyed cited costs that were too high (shipping, tax, fees), and 12% said they could not see or calculate the total order cost up front. Show the total, in the currency that will be charged, on the page with the button. If a card issuer will convert it, say that the final amount in the person's own currency is up to their bank.

4. The rules

Laws about personal data and accessibility arrive at forms because forms are where personal data enters a system and where people most often get stuck. Most of these laws ask, in legal language, for what the earlier sections asked for in design language: collect less, say why, keep it safe, let people in.

RuleWhere and whomWhat it means for a form
GDPRThe EU and EEA; also organizations elsewhere that offer goods or services to people thereCollect only what is necessary for a stated purpose; keep it no longer than needed; consent, where it is the basis, must be an active choice
CCPA as amended by the CPRAFor-profit businesses doing business in California above set thresholdsNotice at or before collection; collection reasonably necessary and proportionate; rights to know, delete, correct and opt out
COPPAUS sites and services directed to children under 13, or that know they collect from themVerifiable parental consent before collecting; no asking a child for more than the activity needs
PCI DSSAnyone who accepts payment cards (a contractual standard, not a law)Keep card data off your own pages and servers: use the processor's hosted fields
ADA, Section 508, European Accessibility ActUS public entities and businesses; US federal agencies; many products and services sold in the EUForms must be usable by disabled people; WCAG is the usual measure

GDPR: minimization and purpose

The General Data Protection Regulation, Regulation (EU) 2016/679, has applied since 25 May 2018. It reaches beyond Europe: a site in San Diego that offers goods or services to people in the EU falls under it for their data. Its Article 5 sets out principles that read like a form designer's checklist. Personal data must be "collected for specified, explicit and legitimate purposes and not further processed in a manner that is incompatible with those purposes" (purpose limitation), and must be "adequate, relevant and limited to what is necessary in relation to the purposes for which they are processed" (data minimisation). It must be kept "for no longer than is necessary" (storage limitation). Article 25 adds that, by default, only the personal data necessary for each specific purpose should be processed. A fifteen-field sign-up that could have been four fields is not only a usability problem in the EU.

The GDPR does not make consent the answer to everything. It lists six lawful bases for processing, and consent is only one. A shipping address needed to deliver an order is processed because of the contract; it needs no consent box. Consent is the basis for things the person could reasonably refuse, such as a marketing newsletter, and then it has to be real.

The GDPR defines consent, in Article 4(11), as "any freely given, specific, informed and unambiguous indication of the data subject's wishes by which he or she, by a statement or by a clear affirmative action, signifies agreement." Recital 32 spells out what that excludes: "Silence, pre-ticked boxes or inactivity should not therefore constitute consent." Article 7 requires that consent can be withdrawn at any time and that "it shall be as easy to withdraw as to give consent."

The Court of Justice of the European Union applied this to a form in the Planet49 case (C-673/17), decided on 1 October 2019. An online lottery's entry form came with a checkbox already ticked, agreeing to cookies for advertising; the Court held that consent is not validly given through a pre-ticked checkbox that the user must deselect to refuse. In form terms: a box that grants permission starts unticked, says exactly what it allows, is not bundled with the terms of service, and is not required to finish the form.

<input type="checkbox" id="offers" name="offers" value="yes" checked> <label for="offers">Send me offers from our partners</label> <form-field> <input type="checkbox" id="news" name="news" value="monthly" aria-describedby="news-hint"> <label for="news">Email me the monthly trail newsletter (optional)</label><br> <output id="news-hint" class="hint" for="news">One email a month. Unsubscribe with one link in any issue.</output><br> </form-field>

The GDPR also sets an age for a child's own consent to online services: 16, which each member state may lower to no less than 13 (Article 8). Below it, a parent must consent.

CCPA and CPRA: California

The California Consumer Privacy Act, amended by the California Privacy Rights Act (Proposition 24, approved in November 2020, with its amendments in effect since 1 January 2023), is the US law students at UC San Diego are most likely to meet first. According to the California Attorney General, it applies to for-profit businesses that do business in California and meet any one of three thresholds: annual gross revenue over $25 million (a figure now adjusted for inflation), buying, selling or sharing the personal information of 100,000 or more California residents or households, or deriving half or more of annual revenue from selling it. It "generally does not apply to nonprofit organizations or government agencies," so the university itself is not covered, but many of the companies that hire its graduates are.

For a form, three parts matter most. A business must give notice "at or before the point of collection" of what it collects and why, which is why a privacy link belongs next to the form, not only in the footer. Since the CPRA, the "collection, use, retention, and sharing" of personal information must be "reasonably necessary and proportionate" to the purposes for which it was collected (Civil Code 1798.100(c)): California's version of data minimization. And consumers have rights to know, delete and correct their data, to opt out of its sale or sharing, including through a browser's Global Privacy Control signal, and to limit the use of sensitive personal information. Personal information of a consumer known to be under 16 may not be sold without opt-in consent, from a parent if the child is under 13.

COPPA: children under 13

The Children's Online Privacy Protection Act and the FTC's COPPA Rule apply to US websites and online services directed to children under 13, and to general sites that know they are collecting personal information from a child under 13. Before collecting, the operator must give notice to parents and obtain verifiable parental consent. The rule also forbids conditioning a child's participation in a game, a prize or another activity on the child giving more personal information than is reasonably necessary for it: data minimization again, written specifically for forms. The FTC amended the rule in 2025, with the changes in effect from 23 June 2025 and compliance required by 22 April 2026; among them, operators need separate parental consent before disclosing a child's data to third parties, and a written policy for how long they keep it.

If a general site needs to screen out children, the question should be neutral: ask for the age or birth year without hinting at the answer that unlocks the site, and do not let the person simply go back and change it.

PCI DSS: do not touch the card

The Payment Card Industry Data Security Standard is not a law. It is a contractual standard set by the PCI Security Standards Council, founded by the major card brands, and every business that accepts cards agrees to it through its payment processor. Its current version, 4.0.1, has hundreds of requirements for any system that stores, processes or transmits card numbers. The practical lesson for a web developer is to make sure none of your systems do.

Payment processors offer two ways to do that. A hosted payment page sends the person to the processor's own page to pay and back again. Hosted fields, sometimes called embedded or iframe fields, put the processor's own card inputs inside your page, each in a frame served from the processor's origin, so the card number travels from the person's browser straight to the processor and your page receives only a token that stands for it. Your form then sends the token, never the number. Either way, never build your own card number field, never log or store a card's security code, and never keep card data in the browser's storage.

Hosted fields reduce your obligations; they do not remove them. A malicious script on the page around the frame can still overlay a fake card form or redirect the frame, which is how skimming attacks on checkout pages work. The standard asks merchants who embed a processor's form to protect that page from such scripts, which section 5 comes back to.

Accessibility law

A form that cannot be completed with a keyboard or a screen reader excludes people, and in many places that is also unlawful. Three bodies of law come up most:

  • The Americans with Disabilities Act (ADA). Title II covers state and local governments, including public universities such as UC San Diego. A Department of Justice rule from April 2024 adopted WCAG 2.1 Level AA as the technical standard for their websites and mobile apps; an interim final rule of 20 April 2026 moved the compliance dates to 26 April 2027 for entities serving 50,000 people or more, and to 26 April 2028 for smaller ones, without changing the standard. Title III covers businesses open to the public; there is no federal regulation setting a technical standard for their websites, but courts hear many suits claiming the ADA reaches them, and inaccessible forms are a common subject.
  • Section 508 of the Rehabilitation Act. It requires US federal agencies to make the technology they build and buy accessible. Since the 2017 refresh of its standards, it incorporates WCAG 2.0 Level AA by reference.
  • The European Accessibility Act. Directive (EU) 2019/882 has applied since 28 June 2025 to a list of products and services sold in the EU, including e-commerce, consumer banking, e-books and passenger transport ticketing. Microenterprises that provide services are exempt. For a web developer, it means the checkout, the account sign-up and the booking form of most sizable businesses selling into Europe must now be accessible by law.

None of these laws says anything a well-built form does not already do. The labels, groups, messages, keyboard order, error handling and zoom support from Organizing Forms and Form Accessibility and Usability are what WCAG asks for. Accessibility has the wider picture.

5. Handling what people give you

The form's job is not over when the request leaves the browser. What the organization does with the data, and who else can see it along the way, decides whether the person's trust was well placed. Some of that is the server's work, which CSE 135 takes up; much of it starts in the page.

Say why you ask, and what happens next

A short reason in a field's hint does more for trust than a long privacy policy nobody reads: "We use your phone number only if the courier cannot find you." "Your email is never shown to other hikers." The <output class="hint"> in the course's pattern is the place for it, and aria-describedby makes sure it is read with the field. Near the submit button, a sentence and a link cover the rest: what the organization will do with the answers, how long it keeps them, and where to ask for them to be deleted. The GDPR's Article 13 and the CCPA's notice at collection both require this kind of information at the moment of collection, so the form is the natural place for it.

Keep it only as long as it is needed

Every record an organization keeps is a record it can lose. A breach cannot expose data that was deleted last year. Decide, when the form is designed, how long each answer is needed and what deletes it: the shipping address after the return window, the contact-form message once it is answered, the draft application if it is never submitted. Remember the copies, too: server logs, analytics, backups, email notifications that paste the whole submission into an inbox, and URLs, because a form sent with GET writes its data into history, logs and the Referer header, as Form Security showed.

Third-party scripts can read every field

Any script running in a page runs with the page's full authority. An analytics library, an advertising tag, a chat widget or a session replay tool can read every field in every form on that page as it is typed, before the person decides to submit, and send it anywhere. Session replay tools are built to record what visitors do, keystrokes included, and they mask sensitive fields only as well as they are configured to.

This is not hypothetical. The Leaky Forms study by Senol, Acar, Humbert and Zuiderveen Borgesius, published at USENIX Security in August 2022, crawled the top 100,000 websites and found that "users' email addresses are exfiltrated to tracking, marketing and analytics domains before form submission and without giving consent on 1,844 websites in the EU crawl and 2,950 websites in the US crawl." The same study found third-party session replay scripts incidentally collecting passwords on 52 websites. Typing an email address into a form and then deciding not to submit it was, on those sites, already too late.

Where a form's data goes: the four zonesFour zones. The client, the browser, holds the form, where the person types; zero trust, because the person, extensions and every script on the page can read and change it. An arrow labeled HTTPS crosses the transit zone to the server, the trusted zone where validation, storage and retention happen. Below the client, a red box for third-party scripts, analytics and session replay, receives a red arrow straight from the form fields, labeled read as typed, before submit. A further arrow from the server to the third-party box is labeled only what you choose to share.client (browser)the form, as typedzero trust: the person,extensions and everyscript can read ittransitHTTPS encrypts itservertrusted: revalidates,sets prices, stores,and deletes on schedulethird-party scripts on the pageanalytics, ads, chat, session replayread as typed, before submitonly what youchoose to share
The four data zones from Foundations, seen from a form. HTTPS protects the trip to the server; nothing in transit protects a field from a script already running in the page.

Three practices follow. Keep third-party scripts off pages with sensitive forms, above all sign-in, payment and anything about health, money or identity; a checkout does not need a chat widget or an ad tag. Where a script must be present, configure it to ignore form fields, and check, in DevTools' network panel, what it actually sends. And use the browser's own limits: a Content Security Policy restricts which scripts may run and which origins the page may send data to, and Subresource Integrity makes sure a script from a CDN is the file you reviewed. None of this reaches browser extensions, which the person installed and the page cannot control.

The four zones

Foundations §16 divides the places data lives into four zones: the client, which the person and every script control and nobody should trust; transit, which HTTPS protects; the server, where validation and decisions belong; and third parties, whose code and storage you are trusting with your users' data. A form touches all four. The design questions on this page map onto them: collect less, so there is less in every zone; let the server decide what matters, such as prices; keep secrets out of the client; and choose third parties as carefully as you would choose who stands behind the person at the counter. Privacy and Security carry these questions through the rest of the course.

6. Where JavaScript goes next

Everything in this section works without a script. That is the point: a form built this way submits, validates, reads aloud, autofills and serves the world on any browser, on a slow connection, with JavaScript blocked or broken. JavaScript makes good forms better; it cannot rescue bad ones. Here is where it goes next, and where the course teaches each part.

Taking over submission

A script can listen for the form's submit event, stop the navigation, gather the fields with new FormData(form), which builds the same entry list the browser would have sent, and send it with fetch(), updating the page with the response instead of loading a new one. Events: forms covers the events and FormData; Client-Side Communication covers the requests, the encodings and what you give up by taking over. The HTML form stays the fallback, so its action and method must keep working.

form.addEventListener('submit', async (event) => { event.preventDefault(); const response = await fetch(form.action, { method: 'POST', body: new FormData(form) }); // now the page owns what the browser did for free: errors, progress, focus, history });

Taking over means taking on the browser's work: showing that something is happening, handling a failed request without losing what was typed, moving focus and announcing the result, and keeping the Back button meaningful. To submit from a script, call form.requestSubmit(), which runs validation and fires the submit event, never form.submit(), which skips both.

Masking and autoformatting

An input mask inserts punctuation as the person types: the parentheses and dash of a US phone number, the spaces in a card number, the slashes in a date. Masks can reduce errors by showing the expected shape, but they cost more than they appear to. The caret jumps as characters are inserted; screen readers announce text the person did not type; pasted and autofilled values get mangled; a mask for one country's phone format locks out every other country's; and input methods for languages such as Japanese and Chinese, which compose characters before committing them, fight with a script that rewrites the field mid-composition.

The gentler pattern is to accept what people type, including spaces and punctuation, and format it after they leave the field, or show the formatted reading in the hint, as the world form does with an amount. Never block a keystroke, never rewrite the value while the person is in the middle of typing it, and never make the server depend on the formatting: it normalizes the value again anyway.

Saving drafts in the browser

A script can copy the answers into localStorage as the person types and put them back if the tab closes or the browser crashes, so a long form is never lost. The course's Storage section, planned, will teach the API. The rule to learn now is what must never go there. localStorage is plain text on the device, kept indefinitely, readable by every script that runs on the same origin, third-party ones included, and visible to the next person on a shared computer. Passwords, card numbers and security codes, one-time codes, government ID numbers, and health or financial details never belong in it. Save drafts only of fields that would be harmless if read, prefer sessionStorage, which ends with the tab, when the draft only needs to survive a reload, and clear the draft as soon as the form is submitted. A draft that matters, such as a long application, belongs on the server, saved with a formnovalidate button as Organizing Forms showed.

Custom validation and custom controls

HTML's constraints cover single fields. Checks that span fields, such as an end date after a start date, or that need the server, such as whether a username is taken, need a script, and the Constraint Validation API from Form Accessibility and Usability lets a script report them through the same channel as the browser's own: setCustomValidity() marks the field invalid with a message, so :user-invalid, the invalid event and the field's <output> all work as before. The server still checks everything again.

When a design needs a control HTML does not have, a rating, a tag picker, a date-range selector, a custom element can become a real form control. A form-associated custom element uses ElementInternals to set its value in the form's entry list, report its validity and take part in labels, disabled fieldsets and form reset like a built-in control. Components: form-associated elements teaches it. It is a far bigger promise than <form-field>, which only holds a label, a control and its messages together: a custom control has to rebuild the keyboard support, the accessible name and role, and the autofill and validation behavior that a native control gives for free. Reach for a native control first.

7. Summary

ConceptKey points
Collect lessEvery field needs a purpose, a user and a reason it cannot be derived. Mark optional fields and say what they improve. Baymard (September 2025): 17% of US shoppers abandoned an order over a too long or complicated checkout; most checkouts could show 20–60% fewer form elements.
NamesOne "Full name" field, accepting any characters; an optional "What should we call you?". No patterns or minimum lengths on names.
Addresses and phonesCountry first; general fields, loosely checked; postal code as optional text; tokens such as address-level1 and postal-code. type="tel" with autocomplete="tel", accepting punctuation and country codes.
Dates, gender, titlestype="date" sends ISO dates; three fields for memorable dates. Ask gender or titles only when needed, optionally, with inclusive answers.
Language and directionlang on the page and on fields in another language; dir="auto" on text fields; dirname sends the direction (Baseline widely available). UTF-8 end to end.
MoneySeparators differ by locale. A text field with inputmode="decimal", read deliberately and read back; type="number" for counts. State the currency, never infer it. The form sends choices; the server sets and charges the price.
The rulesAwareness, not advice. GDPR: purpose limitation, minimization, storage limitation, consent never pre-ticked (Recital 32, Planet49). CCPA/CPRA: notice at collection, proportionate collection, consumer rights. COPPA: parental consent under 13. PCI DSS: hosted fields, never your own card input. ADA, Section 508, the EAA (since 28 June 2025): accessible forms.
HandlingSay why in the hint and what happens next by the button. Decide retention up front, copies included. Third-party scripts can read fields before submit (Leaky Forms, 2022): keep them off sensitive forms. Four zones: trust only the server.
JavaScript nextfetch with FormData over a working form; requestSubmit(). Format after typing, not during. Drafts in storage only for harmless fields, cleared on submit. setCustomValidity() for cross-field checks; form-associated custom elements when no native control fits.

The section has gone from a form's request to its fields, its organization, its usability, its security and finally the people it serves. JavaScript, frameworks and servers all come later, and all of them build on what the form already is. HTML is the start; get it wrong here and nothing later fixes it.