Make forms as simple as possible and only ask what is absolutely needed to complete the task.
General
Content
Do not ask for two or more pieces of personally identifiable information (PII).
The form must be on a secure page (https) sent to a secure location (e.g. a password protected server on an internal network).
If the data being requested is critical, contains a lot of PII, or is duplicative of data already available in a database, utilize existing resources or databaess (requires log in) to avoid manually entering the data or offer to auto-fill fields that may be already stored in their browser.
Ask only for critical data to keep the forms as brief as possible. Some data may not be needed in the initial form submission (it can be collected at a later stage of an interaction).
Ensure the form speaks with one voice, despite questions from several different people or departments.
If a field is optional, it may not need to be a part of the form. Consider removing any non-required fields.
Design
Do not provide a “Clear” or “Reset” button for data submission forms. A “clear” button should only be used for a form that, after posting without errors, retains data in the fields and is visually different from the “Send” button.
Red text is used only for warnings and error messages.
Upon successful form submission, provide a success message and path out of form or to the next step. Avoid success message page dead ends.
Form validation requires both HTML and server (or javascript) detection processes. Utilize HTML regex patterns and required attributes and provide sufficient error messaging for a person to easily update.
Use 50% to 75% of the height of a single input field between adjacent inputs. (Web Form Design, Wroblewski)
Design the form to reduce ambiguity while not adding cognitive burden to the person filling it out. For instance, a date is 3 text fields with appropriate attributes to reduce input errors. This removes the requirement for a person to use a specific punctuation pattern.
To prevent spam and other automated attacks, use hidden validation techniques such as Honeypot that do not disrupt the user experience. Avoid CAPTCHA methods.
Present fields in a single-column layout. This keeps visual momentum moving down the page so users don’t have to reorient themselves with multiple columns. (Exceptions to this rule are short, logical fields that may be presented on the same row like City, State, and Zip code.)
Ensure form fields are visibly labeled.
Make sure form fields have clearly defined boundaries or outlines so that people with cognitive disabilities know the size and location of the click target.
Do not use placeholder text in form fields. Placeholder text causes usability issues because it disappears when content is entered into the form field. Hints and instructions should be persistent and placed outside of the field.
Provide highly visible and specific error states. Use multiple cues like color, icons, bold font weight, heavy border or outline, and helpful text to make sure users don’t overlook this critical information.
Forms that employ inclusive design have a higher completion rate. To make it easy to navigate through the form, at minimum:
create a clear path through the form with generous whitespace between questions,
avoid multi-column forms and misaligned appearance, and
make it keyboard navigable.
Language
Use active neutral language
Avoid triggering or judgmental verbiage
Keep it short. Use bullet points. Remove excess words.
Give the form a clear concise title. Identify whom the form is for and its purpose at the start.
Avoid unnecessary or repeated questions.
Don’t force people to answer or choose an option that doesn’t fit them.
If you cannot explain to the person why data is asked for, don’t ask for it.
Conduct a question protocol to verify every piece of information asked of a person is intentional and appropriate by considering:
Who within the organization uses the answer
What they use them for
Whether an answer is required or optional
If an answer is required, what happens if a user enters any old thing just to get through the form
Labels
Every input requires an attached label. Four methods are available.
Preferred methods
These two methods are preferred because they provide the most visibility and clarity for the least amount of code.
<label> + <input>
The most traditional approach to pairing a label with an input is to give the input element a unique id that the label can refer to with the for attribute.
Embedding the input element within the label element, the input is implicitly connected to the label, eliminating the need for an id on the input as well as the for attribute on the label.
These are less than ideal because they hide the text for people with sight who would also benefit from the clarification, or they rely on assistive technology to properly announce the text in a meaningful order while adding code complexity.
Screen reader only hidden label
Using aria-label is specifically for assistive technology to detect. Using this method is only suggested if the input has clear intent by its context, and even then one assumes people without visual impairment are able to interpret intent correctly.
Use sentence casing and keep labels to 1 or 2 words
Use consistent labels. Check the glossary for standard terms. Standard fields:
Name
Date of birth
Street address
City
State
Zip code
Email
Primary phone
Secondary phone
Placeholder hints
Never use the placeholder attribute. Placeholder contrast is inefficient, its placement may confuse users, and it disappears, forcing a person to recall.
If additional instruction is needed for an input field, use the following methods.
Input group instructions
Use a fieldset to group related input elements together, and use the aria-describedby attribute to indicate the element with instructions.
<fieldsetaria-describedby="date-hint"role="group"><legend><h3>When was your ID issued?</h3></legend><pid="date-hint">Example, 01 08 2007</p><divclass="row"><label>
Day <inputid="date-day"name="day"type="number"pattern="[0-9]*"></label><label>
Month <inputid="date-month"name="month"type="number"pattern="[0-9]*"></label><label>
Year <inputid="date-year"name="year"type="number"pattern="[0-9]*"></label></div></fieldset>
Instructions for single field
Use official umn.edu address
<labelfor="email">Email address</label><pid="email-hint"class="alert alert-inline"><svgclass="glyph"aria-hidden="true"focusable="false"viewBox="0 0 16 16"><gfill="currentColor"><pathd="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM8,2a6,6,0,1,0,6,6A6,6,0,0,0,8,2Z"/><pathd="M8,12a1,1,0,0,1-1-1V8A1,1,0,0,1,9,8v3A1,1,0,0,1,8,12Z"/><circle>cx="8"cy="5"r="1"/></g></svg>
Use official umn.edu address
</p><inputid="email"name="email"type="email"spellcheck="false"pattern=".+\@umn.edu$"aria-describedby="email-hint"/>
Related inputs
Group similar questions together with a useful heading using <fieldset> and <legend>.
<fieldset><legend>Current status</legend><label><inputtype="checkbox"name="option1">Employed?</label><label>ID number <input type="text"name="entry1"></label></fieldset>
Required vs. optional
Clearly mark mandatory fields.
If all fields are required, state “All fields are required” at the beginning of the form.
If logical, place all optional fields at the end of the form and label them “(optional)”. More importantly, if the field is optional, consider whether it is necessary to have it on the form.
Required fields must have required attribute as well as aria-required="true". Some assistive technology does not correctly identify native required so the ARIA form is also necessary.
To identify required fields, use one of the following patterns:
Pattern 1
Add the text “required” inside the label.
<p>* All fields marked with an asterisk are <spanid="req-hint">required</span>.</p><labelaria-describedby="req-hint">Name <inputtype="text"requiredaria-described="true"/></label>
Pattern 2
Insert content with CSS based on the required attribute.
* All fields marked with an asterisk are required.
<p>* All fields marked with an asterisk are <spanid="req-hint">required</span>.</p><labelaria-describedby="req-hint">Name <inputtype="text"requiredaria-required="true"/></label>
Input types
Use <select> for pre-determined lists over 5 items. Use multiple attribute when the list replaces checkbox items.
Choose the best input type, avoid using “text” as a default if better options exist. Available input types in HTML5:
button
Adds button-like functionality to a form.
checkbox
Allows for multiple value selection. A person may select zero to all of the options (group inputs together by using
the same name attribute, e.g. <input type="checkbox" name="set" /> <input type="checkbox" name="set" />).
color
Use with caution. As of December 2021, global browser support is 96% (75% full support and additional 21% partial support): IE11 and Opera Mini have no support, as well as fairly older versions of all major browsers.
An advanced <select> dropdown with color swatches and can open the OS or other internal color picker.
date
Use with caution. As of December 2021, global browser support is 96%. However, 21% is partial support primarily for no support of week or month in Firefox and Safari, and additionally no min, max, or step support in mobile Safari. No support for IE 11 and Opera Mini.
Provides a browser’s internal calendar tool without the need of javascript. Support and consistency is uneven so not recommended. Additional attributes may improve the experience by adding min and max dates in ISO format.
datetime and datetime-local
Use with caution. See date support statement.
Combines the built in calendar widget with the time spinner set to UTC time zone. datetime-local adds time zone variation. Not recommended due to accessibility and functionality issues.
email
If email is required (<input type="email" required />), the browser itself may check for valid email formats. Multiple email addresses may be entered. On some mobile devices, a specialized virtual keyboard is available for email addresses.
file
Use with caution. As of December 2021, the main site has 96% support, lack of support mostly exists in mobile browsers. If file upload is critical to the form and is expected on mobile devices, use other methods.
Provides a “Browse...” button to search the local device for a file to upload and includes a status statement such as “No file selected.”.
hidden
To pass necessary parameters the person does not need to see or input. Typical usage is to pass additional search parameters to a search engine.
month
Do not use. See date support statement.
Opens the built in browser calendar widget but only allows selection of month and year.
number
Number inputs can be powerful when combining other attributes such as min, max, step, and an initial value. For some browsers, the input field will be accompanied by a number spinner (up and down arrows). Site styles override the spinner feature for most browsers.
password
The characters in the input field are masked (shown as asterisks or circles).
radio
Allows a user to select only one in a set of radio buttons (radio inputs are grouped together by using the same name attribute, e.g. <input type="radio" name="set" /> <input type="radio" name="set" />). Requires more than one radio option.
range
When the number does not need to be exact, range can be used to provide a “slider” interface with min and max values.
search
Styled similarly to the text type. May be used to target search input fields for styling or behavior modifications. Has benefits such as changing the mobile keyboard “Go” to “Search”, some browsers allow Esc to clear text, and some offer an “x” to clear the field. More about “styled search component”.
submit
Associate input and submit buttons with a form.
tel
For telephone numbers. Primarily useful on mobile devices that may open a numeric virtual keyboard.
text
Text inputs are the most common type offering a one line input field. For browsers that do not support the newer input types, they will default unsupported types to text types.
time
Do not use. See date support statement.
Defaults to an input field with a spinner in the 24-hour clock.
url
If URL is required (<input type="url" required />), the browser itself will check for valid URL formats. On some mobile devices, a specialized virtual keyboard is available for email addresses.
week
Do not use. See date support statement.
Opens the built in browser calendar widget with an additional week selection column. The result is the year along with the week number (e.g. 2015-W23).
Be mindful of what types are supported. Also be mindful of what data should be accepted in fields. For instance, make no assumptions about a person’s name — whether they have a first, last, middle, non-hyphenated, ASCII-only name. Read Kalzumeus’ article “Falsehoods programmers believe about names” about some assumptions we make about names.
Auto-complete and auto-suggest HTML features
Use autocomplete smartly. Include on every input, even with a basic "on" or "off" value.
Autocomplete is helpful if someone has saved their data to their browser for future use, which may quickly speed up the form process by pre-populating the fields with the browser-saved content. This helps most people but especially those using assistive technology, with motor limitations, with attention concerns, and with cognitive limitations.
To enable this feature more consistently across browsers, identify the input content type with semantic markup, autocomplete.
Autocomplete may have multiple values, similar to the class attribute. List of available autocomplete values:
name
honorific-prefix
given-name
additional-name
family-name
honorific-suffix
nickname
username
new-password
current-password
organization-title
organization
street-address
address-line1
address-line2
address-line3
address-level4
address-level3
address-level2
address-level1
country
country-name
postal-code
cc-name
cc-given-name
cc-additional-name
cc-family-name
cc-number
cc-exp
cc-exp-month
cc-exp-year
cc-csc
cc-type
transaction-currency
transaction-amount
language
bday
bday-day
bday-month
bday-year
sex
url
photo
Dates
Do not use select or other dropdown tools. Entering the dates with a keyboard is far quicker than navigating dropdown lists. If a datepicker is desired, do not make it the only method to provide the data; have it as a supplemental input method second to the input field.
Multi-page forms
For pages with “previous” and “next”, use hyperlinks where possible with appropriate hyperlink markup.
<olrole="progressbar"aria-valuenow="1"aria-valuemin="0"aria-valuetext="Step 1 of 3"aria-valuemax="3"><liaria-current="step"><span>Step one</span></li><li><span>Step two</span></li><li><span>Step three</span></li></ol><olrole="progressbar"aria-valuenow="2"aria-valuemin="0"aria-valuetext="Step 2 of 3"aria-valuemax="3"><li><span>Step one</span></li><liaria-current="step"><span>Step two</span></li><li><span>Step three</span></li></ol><olrole="progressbar"aria-valuenow="3"aria-valuemin="0"aria-valuetext="Step 3 of 3"aria-valuemax="3"><li><span>Step one</span></li><li><span>Step two</span></li><liaria-current="step"><span>Step three</span></li></ol>
Form elements
Checkboxes and radio buttons
Use <fieldset> to surround the entire grouping of checkboxes or radio buttons. Use <legend> to provide a description (for example, the question) for the grouping.
Some assistive technology reads the legend text for each fieldset, so it should be brief and descriptive. This helps someone using assistive technology to understand the question they are answering with the group of checkboxes.
<fieldset><legend>What services do you use?</legend><inputtype="checkbox"name="services"id="cb1"/><labelfor="cb1">Tutoring</label><inputtype="checkbox"name="services"id="cb2"/><labelfor="cb2">Interlibrary Loan</label><inputtype="checkbox"name="services"id="cb3"disabled/><labelfor="cb3">Course reserves</label><inputtype="checkbox"name="services"id="cb4"/><labelfor="cb4">Makerspaces</label></fieldset>
Radio buttons
<fieldset><legend>Does your request include items that may have a copyright fee?</legend><inputtype="radio"name="copyright"id="rb1"/><labelfor="rb1">Yes</label><inputtype="radio"name="copyright"id="rb2"/><labelfor="rb2">No</label><inputtype="radio"name="copyright"id="rb3"/><labelfor="rb3">I don’t know</label></fieldset>
Toggles
When presenting a yes/no question, a toggle may be a friendlier interface option.
Where response format preference or tips may help, add a hint. Apply server side processing to handle most input concerns.
Please use your university email if available.
<labelfor="t1">Email address</label><pclass="alert alert-inline"id="t2-hint"><svgclass="glyph"aria-hidden="true"focusable="false"viewBox="0 0 16 16"><gfill="currentColor"><pathd="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM8,2a6,6,0,1,0,6,6A6,6,0,0,0,8,2Z"/><pathd="M8,12a1,1,0,0,1-1-1V8A1,1,0,0,1,9,8v3A1,1,0,0,1,8,12Z"/><circlecx="8"cy="5"r="1"/></g></svg>
Please use your university email if available.
</p><inputtype="email"name="email"id="t1"/>
File field
Browsers do not allow styling the file field, so to create a similar experience to the default Javascript is required. If preferred, a recommended custom styling option is at styling and customizing file inputs the smart way.
Errors for each field are inserted between the label and the input field with the input field pointing to it using aria-describedby. If the input field is already pointing to a hint, place the error messages above the hint, and present them first in the aria-described attribute, i.e. aria-describedby="t2-error t2-hint".
Error messages must be short and precise.
Email addresses require an @ symbol.
Please use your university email if available.
<labelfor="t2">Email address</label><pclass="alert alert-inline alert-danger"id="t2-error"><svgclass="glyph"aria-hidden="true"focusable="false"viewBox="0 0 16 16"><gfill="currentColor"><pathd="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,14a6,6,0,1,1,6-6A6,6,0,0,1,8,14Z"/><pathd="M10.83,5.17a1,1,0,0,0-1.41,0L8,6.59,6.59,5.17A1,1,0,0,0,5.17,6.59L6.59,8,5.17,9.41a1,1,0,1,0,1.41,1.41L8,9.41l1.41,1.41a1,1,0,0,0,1.41-1.41L9.41,8l1.41-1.41A1,1,0,0,0,10.83,5.17Z"/></g></svg>
Email addresses require an @ symbol.
</p><pclass="alert alert-inline"id="t2-error t2-hint"><svgclass="glyph"aria-hidden="true"focusable="false"viewBox="0 0 16 16"><gfill="currentColor"><pathd="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM8,2a6,6,0,1,0,6,6A6,6,0,0,0,8,2Z"/><pathd="M8,12a1,1,0,0,1-1-1V8A1,1,0,0,1,9,8v3A1,1,0,0,1,8,12Z"/><circlecx="8"cy="5"r="1"/></g></svg>
Please use your university email if available.
</p><inputname="t2"id="t2"type="text"aria-invalid="true"aria-describedby="t2-hint"/>
Success
Success messaging for individual form fields is only necessary for dynamic pages that validate data on the fly.
Name is found in our system.
<labelfor="t3">Name</label><pclass="alert alert-inline alert-success"id="t3-success"><svgclass="glyph"aria-hidden="true"focusable="false"viewBox="0 0 16 16"><gfill="currentColor"><pathd="M10.2,5.4,7.1,9.53,5.67,8.25a1,1,0,1,0-1.34,1.5l2.05,1.82a1.29,1.29,0,0,0,.83.32h.12a1.23,1.23,0,0,0,.88-.49L11.8,6.6a1,1,0,1,0-1.6-1.2Z"/><pathd="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,14a6,6,0,1,1,6-6A6,6,0,0,1,8,14Z"/></g></svg>
Name is found in our system.
</p><inputname="t3"id="t3"type="text"value="Goldy Gopher"aria-invalid="false"aria-describedby="t3-success"/>
<tablerole="presentation"><thead><tr><td></td><th>Disagree</th><th>No opinion</th><th>Agree</th></tr></thead><tbody><trrole="group"><th>Trees are awesome</th><td><inputtype="radio"name="trees"id="r20"/><labelfor="r20"><span>Trees are awesome</span><span>Disagree</span></label></td><td><inputtype="radio"name="trees"id="r21"/><labelfor="r21"><span>Trees are awesome</span><span>No opinion</span></label></td><td><inputtype="radio"name="trees"id="r22"/><labelfor="r22"><span>Trees are awesome</span> <span>Agree</span></label></td></tr><trrole="group"><th>Water is good</th><td><inputtype="radio"name="water"id="r23"/><labelfor="r23"><span>Water is good</span> <span>Disagree</span></label></td><td><inputtype="radio"name="water"id="r24"/><labelfor="r24"><span>Water is good</span><span>No opinion</span></label></td><td><inputtype="radio"name="water"id="r25"/><labelfor="r25"><span>Water is good</span> <span>Agree</span></label></td></tr></tbody></table>
<fieldset><legend>Request date</legend><divclass="form-date"><label>
Month
<inputtype="text"name="month"pattern="[0-9]*"minlength="1"maxlength="2"autocorrect="off"inputmode="numeric"/></label><label>
Day
<inputtype="text"name="day"pattern="[0-9]*"minlength="1"maxlength="2"autocorrect="off"inputmode="numeric"/></label><label>
Year
<inputtype="text"name="year"pattern="[0-9]*"minlength="2"maxlength="4"autocorrect="off"inputmode="numeric"/></label></div></fieldset>