Web forms

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.

Accessibility

From Accessibility for Teams visual design for forms.

  • 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.


<label for="search">Search</label>
<input id="search" name="search" type="text" />
<input> embedded in <label>

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.


<label>Search <input name="search" type="text" /></label>

Less ideal though valid methods

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.


<input type="text" name="search" aria-label="Search" />
ARIA to tie two elements together

This method allows for the label to be something other than a label element.


<input aria-labelledby="search-button" name="search" type="text"  />
<button id="search-button" type="submit">Search</button>

Language notes

  • 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.

When was your ID issued?

Example, 01 08 2007


<fieldset aria-describedby="date-hint" role="group">
  <legend>
    <h3>When was your ID issued?</h3>
  </legend>
  <p id="date-hint">Example, 01 08 2007</p>
  <div class="row">
    <label>
       Day <input id="date-day" name="day" type="number" pattern="[0-9]*">
    </label>
    <label>
      Month  <input id="date-month" name="month" type="number" pattern="[0-9]*">
    </label>
    <label>
      Year  <input id="date-year" name="year" type="number" pattern="[0-9]*">
    </label>
  </div>
</fieldset>

Instructions for single field

Use official umn.edu address


<label for="email">Email address</label>
<p id="email-hint" class="alert alert-inline">
<svg class="glyph" aria-hidden="true" focusable="false" viewBox="0 0 16 16">
 <g fill="currentColor">
 <path d="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" />
 <path d="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>
<input id="email" name="email" type="email" spellcheck="false" pattern=".+\@umn.edu$" aria-describedby="email-hint" />

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 <span id="req-hint">required</span>.</p>
  <label aria-describedby="req-hint">Name <input type="text" required aria-described="true"  /></label>
  
  

Pattern 2

Insert content with CSS based on the required attribute.

  
    <style type="text/css">label + input[required] {content: " (required)";}</style>
  <label for="input-1">Name/></label>
  <input type="text" required aria-described="true" </input>
  
  

Pattern 3

* All fields marked with an asterisk are required.

  
  <p>* All fields marked with an asterisk are <span id="req-hint">required</span>.</p>
  <label aria-describedby="req-hint">Name <input type="text" required aria-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.

Paging


<a href="/page1" rel="prev">Previous</a> | <a href="/page3" rel="next">Next</a>

Progress indicator

Always indicate where the person is in the form (how many pages remain, how many total pages).

  1. Step one
  2. Step two
  3. Step three
  1. Step one
  2. Step two
  3. Step three
  1. Step one
  2. Step two
  3. Step three

  <ol role="progressbar" aria-valuenow="1" aria-valuemin="0" aria-valuetext="Step 1 of 3" aria-valuemax="3">
    <li aria-current="step"><span>Step one</span></li>
    <li><span>Step two</span></li>
    <li><span>Step three</span></li>
  </ol>

  <ol role="progressbar" aria-valuenow="2" aria-valuemin="0" aria-valuetext="Step 2 of 3" aria-valuemax="3">
    <li><span>Step one</span></li>
    <li aria-current="step"><span>Step two</span></li>
    <li><span>Step three</span></li>
  </ol>

  <ol role="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>
    <li aria-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.

Adapted from A11y Style Guide, create custom keyboard accessible checkboxes, and create custom keyboard accessible radio buttons.

Checkboxes

What services do you use?

<fieldset>
  <legend>What services do you use?</legend>

  <input type="checkbox" name="services" id="cb1" />
  <label for="cb1">Tutoring</label>

  <input type="checkbox" name="services" id="cb2" />
  <label for="cb2">Interlibrary Loan</label>

  <input type="checkbox" name="services" id="cb3" disabled />
  <label for="cb3">Course reserves</label>

  <input type="checkbox" name="services" id="cb4" />
  <label for="cb4">Makerspaces</label>
</fieldset>

Radio buttons

Does your request include items that may have a copyright fee?

<fieldset>
  <legend>Does your request include items that may have a copyright fee?</legend>

  <input type="radio" name="copyright" id="rb1" />
  <label for="rb1">Yes</label>

  <input type="radio" name="copyright" id="rb2" />
  <label for="rb2">No</label>

  <input type="radio" name="copyright" id="rb3"/>
  <label for="rb3">I don’t know</label>

</fieldset>

Toggles

When presenting a yes/no question, a toggle may be a friendlier interface option.

Toggle functionality and styles adapted heavily from Adrian Roselli’s under engineered toggles.

Toggles should also include textual indicators, such as “no or yes” or “disabled or enabled” for each state.


  <input type="checkbox" name="pubalerts" id="i-pubalerts" class="toggle" />
  <label for="i-pubalerts">I agree to the terms and conditions.</label>

  <input type="checkbox" name="pubalerts" id="i-pubalerts" class="toggle flip" />
  <label for="i-pubalerts">I agree to the terms and conditions.</label>

Text inputs

These patterns apply to <textarea> and input types text, search, email, number, password, tel, and url.

Basic text field


  <label for="t0">Name</label>
  <input type="text" name="name" id="t0" />

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.


<label for="t1">Email address</label>
<p class="alert alert-inline" id="t2-hint">
 <svg class="glyph" aria-hidden="true" focusable="false" viewBox="0 0 16 16">
  <g fill="currentColor">
  <path d="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" />
  <path d="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>
  Please use your university email if available.
</p>
<input type="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.

Accepted file types: PDF, DOCX


  <label for="f1">Reading list</label>
  <p class="alert alert-inline" id="f1-hint">Accepted file types: PDF, DOCX</p>
  <input name="readinglist" id="f1" type="file" aria-describedby="f1-hint" />

Number field


  <label for="n1">Number of copies needed</label>
  <input name="n1" id="n1" type="number" min="1" max="100" />

Textarea


  <label for="ta1">Description</label>
  <textarea name="ta1" id="ta1"></textarea>

Feedback

See also alerts.

Errors

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.


<label for="t2">Email address</label>
<p class="alert alert-inline alert-danger" id="t2-error">
 <svg class="glyph" aria-hidden="true" focusable="false" viewBox="0 0 16 16">
  <g fill="currentColor">
   <path d="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" />
   <path d="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>
<p class="alert alert-inline" id="t2-error t2-hint">
 <svg class="glyph" aria-hidden="true" focusable="false" viewBox="0 0 16 16">
  <g fill="currentColor">
  <path d="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" />
  <path d="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>
  Please use your university email if available.
</p>
<input name="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.


<label for="t3">Name</label>
<p class="alert alert-inline alert-success" id="t3-success">
  <svg class="glyph" aria-hidden="true" focusable="false" viewBox="0 0 16 16">
   <g fill="currentColor">
    <path d="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" />
    <path d="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>
<input name="t3" id="t3" type="text" value="Goldy Gopher" aria-invalid="false" aria-describedby="t3-success" />

Select

Adapted from the Filament Group, styling a select like it’s 2019.


<label for="s1">Options</label>
<select name="options" id="s1">
 <option disabled></option>
 <option value="1">Option 1</option>
 <option value="2">Option 2</option>
 <optgroup label="Option 3">
  <option value="3a">Option 3a</option>
  <option value="3b">Option 3b</option>
 </optgroup>
</select>

Matrix

  Disagree No opinion Agree
Trees are awesome
Water is good

<table role="presentation">
 <thead>
  <tr>
    <td> </td>
    <th>Disagree</th>
    <th>No opinion</th>
    <th>Agree</th>
  </tr>
 </thead>
 <tbody>
  <tr role="group">
    <th>Trees are awesome</th>
    <td>
      <input type="radio" name="trees" id="r20" />
      <label for="r20"><span>Trees are awesome</span> <span>Disagree</span></label>
    </td>
    <td>
      <input type="radio" name="trees" id="r21" />
      <label for="r21"><span>Trees are awesome</span><span>No opinion</span></label>
    </td>
    <td>
      <input type="radio" name="trees" id="r22" />
      <label for="r22"><span>Trees are awesome</span> <span>Agree</span></label>
    </td>
  </tr>
  <tr role="group">
    <th>Water is good</th>
    <td>
      <input type="radio" name="water" id="r23" />
      <label for="r23"><span>Water is good</span> <span>Disagree</span></label>
    </td>
    <td>
      <input type="radio" name="water" id="r24" />
      <label for="r24"><span>Water is good</span> <span>No opinion</span></label>
    </td>
    <td>
      <input type="radio" name="water" id="r25" />
      <label for="r25"><span>Water is good</span> <span>Agree</span></label>
    </td>
  </tr>
 </tbody>
</table>

Form groups

Search


<form action="//stacks.lib.umn.edu/janus" aria-label="Search Libraries resources" method="get" role="search" class="search">
 <div class="input-group">
  <div class="input-group-prepend">
  <select name="target" aria-label="Resource" class="btn-secondary">
   <option value="Primo">Libraries search</option>
   <option value="PubMed">PubMed</option>
   <option value="WorldCat">WorldCat</option>
   <option value="UMedia">UMedia</option>
   <option value="GoogleCustomSearch">Libraries website only</option>
  </select>
 </div>
 <input id="form-input-text" class="form-control" name="search" required="required" type="search" aria-label="Search" />
 <div class="input-group-append">
  <button type="submit" class="btn-ghost">
   <svg class="glyph glyph-search" viewBox="0 0 30 32" width="30" height="32" focusable="false" aria-hidden="true">...</svg>
   <span class="visuallyhidden-mobile">Search</span>
  </button>
  </div>
 </div>
</form>

Date fields

Request date

<fieldset>
  <legend>Request date</legend>
  <div class="form-date">
    <label>
      Month
      <input type="text" name="month" pattern="[0-9]*" minlength="1" maxlength="2" autocorrect="off" inputmode="numeric" />
    </label>
    <label>
      Day
      <input type="text" name="day" pattern="[0-9]*" minlength="1" maxlength="2" autocorrect="off" inputmode="numeric" />
    </label>
    <label>
      Year
      <input type="text" name="year" pattern="[0-9]*" minlength="2" maxlength="4" autocorrect="off" inputmode="numeric" />
    </label>
  </div>
</fieldset>