Forms, Form Validation, and CAPTCHAs

On the web, forms are constantly being used to collect information from users: signing up for something, buying something, asking a question, or contacting someone. Since forms are so commonly used, it is imperative to make forms accessible for all users.

Best Practices

These best practices have used substantial information from the US design standards guide.

Form Layout

  • A set of input fields within a form should be grouped by fieldset elements if they are related.

  • Do not use auto-advance in your form. (This is terrible for people with disabilities – don’t do it)!

  • Do not rearrange the order of the form, or inputs, with CSS. (This can cause extreme confusion for screen readers, and their users).

  • Ideally, present only one or two inputs per line for users with limited vision who have trouble scanning the screen horizontally.

  • Ensure that your color/contrast ratios and typography are accessible.

  • Each fieldset should have a legend element (directly under the first fieldset tag) that describes the grouping.

  • These practices give screen readers and users of assistive technology more information about the form, allowing them to better fill it out.

  • Every input element in a form should have a related label. You can either have a hybrid label, which is recommended for accessibility, or an explicit label.

    • Hybrid labels: These are labels which surround their associated input.
    • Explicit labels: These are labels which precede or are adjacent to their corresponding input.
  • Your form submission button should have type="submit" and have, like all buttons, a clear, actionable title. Do not use auto-submission after the user has filled out the last input.

    • Example: “Send Message”, “Submit Message”, “Subscribe”

Form Inputs

This information applies to all sorts of valid inputs: text inputs, textarea elements, telephone numbers, address entry, select elements, checkboxes, radio buttons, and date inputs (we have specifics on some of these types of inputs below).

  • All form inputs should have a related, unique label that either wraps it, or precedes it. The label for attribute should match its input’s id element, regardless of whether it wraps the element or not.

  • Try to give all inputs a type='' attribute (types include email, tel, text, submit, etc.). When supported by a browser, they improve the experience of all users.

  • If the input is required, put “Required” or “(required)” within a span in the label. Consider not using “*” to indicate required inputs as it is often not read by screen readers.

    • Example: <label for="name">First Name <span>(required)</span></label>
    • Also, within the input, include an HTML5 required='' attribute so that you can use JavaScript form validation. (If you use both the HTML5 required and aria-required attributes in the input element, a screen reader will end up reading “required” twice, which is a bit annoying).
    • Also, for required inputs, you can include regular expression pattern information, or even max-length of characters in the input attributes, which many screen readers can understand.
  • Do not use placeholder text. Placeholder text poses a variety of accessibility issues (including possible problems with color/contrast, users thinking the form input is already filled out, and placeholder text replacing a form label).

    • Give all the information about what is required to fill out the input in the form label, not the placeholder.
  • If you have required inputs, use JavaScript to visually and physically align validation messages with labels for certain input fields (that way, a screen reader will read out the error while reading over the label).

Inputs requiring numbers

  • Try not to break numbers into distinct inputs (such as phone numbers, Social Security Numbers, or credit card numbers).

    • The US Design Standards advise: “For example, use one input for [each] phone number, not three (not one for area code, one for local code, and one for number). Each field needs to be labeled for a screen reader and the labels for fields broken into segments are often not meaningful.”

Checkboxes, Radio Buttons

  • All related checkboxes should be surrounded by unordered list and a fieldset with a legend tag. The same goes for a set of related radio buttons. However, for a single checkbox, or single radio button, do use a fieldset and legend.

  • Since the only label associated with a checkbox or radio button is the option itself - e.g. ‘Yes,’ 'No,’ 'Banana,’ it is important to associate the option with a legend id (the legend could be: 'Would you like to be on our mailing list?’). Place an aria-labelledby='{id of legend element}' on the label or the unordered list surrounding a set of related checkboxes/radio buttons. Also, place an aria role='radiogroup' or role='group' on the surrounding element as well. View our code snippets below for further details.

Select inputs

  • Selects are by far the most cognitively and technically challenging input. Consider using another input, such as a checkbox or radio button instead.

Date input

  • The US Design Standards states that for an input which required a month, day, and year, “Three text fields are the easiest way for users to enter most dates.”

Code Snippets

Below we have supplied the code for a variety of accessible form inputs. There are many ways to use jQuery/JavaScript to make your forms accessible, and through testing and research, we have found our own unique solution below.

Our solution takes advantage of the jQuery .validity.valid, and applying an aria-live='assertive' attribute to the first new error message on the form. (The error message must be dynamically added for this aria-live message to be read). Also, we have found that if there are multiple aria-live regions, a screen reader will only read the last one on the page, so there should really only be one aria-live region ever on a page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<form class="form-example" method="post">
  <fieldset>
    <legend>Personal Information</legend>

    <label for="full-name">
      Full Name
      <span class="required">
        (required)
      </span>

      <span class="error-message">
          You must input a real name.
      </span>

      <input id="full-name" name="full-name" required="" type="text">

    </label>

    <label for="email">
      Email
      <span class="required">
        (required)
      </span>

      <span class="error-message">
        The email address you entered is not valid.
      </span>

      <input id="email" name="email" required="" type="email">

    </label>

  </fieldset>

  <fieldset>
    <legend>Credit Card Information</legend>

    <label for="cc">
      Credit Card Number
      <span class="required">
        (required)
      </span>

      <span class="error-message">
          Your credit card number should be all numbers.
      </span>

      <input id="cc" name="cc" required="" type="text" minlength='13' maxlength='20' pattern='\s*[0-9]+-?\s*[0-9]+-?\s*[0-9]+-?\s*[0-9]+-?\s*'>

    </label>
  </fieldset>

  <fieldset>
    <label for='text-comments'>
      Please leave your comments or questions here
      <span class="required">
        (required)
      </span>

      <span class="error-message">
        Please give us a little more information about your inquiry.
      </span>

      <textarea id='text-comments' required=''></textarea>
    </label>
  </fieldset>

  <fieldset>
    <legend id='legend-1'>Can we add you to our email mailing list? <span class="required">(required)</span></legend>

    <ul aria-labelledby='legend-1' role='radiogroup'>
      <li>
        <label for="yes">
          <span class="error-message">
            Please select yes or no.
          </span>

          <input id="yes" required="" type="radio" name="answers" value="yes">

          Yes
        </label>
      </li>
      <li>
        <label for="no">
          <input id="no" type="radio" name="answers" value="no">

          No
        </label>
      </li>
    </ul>
  </fieldset>

  <fieldset>
    <legend id='legend-2'>Which topics interest you? <span class="required">(required)</span></legend>

    <ul aria-labelledby='legend-2' role='group'>
      <li>
        <label for="science">
          <span class="error-message">
            Please select at least one category.
          </span>

          <input id="science" required="" type="checkbox" name="categories" value="science">

          Science
        </label>
      </li>
      <li>
        <label for="children-programs">
          <input id="children-programs" required="" type="checkbox" name="categories" value="children-programs">

          Programs for Children
        </label>
      </li>
      <li>
        <label for="new-events">
          <input id="new-events" required="" type="checkbox" name="categories" value="new-events">

          New Events
        </label>
      </li>
    </ul>
  </fieldset>

  <fieldset>
    <label for="options">Choose from the following:
      <span class="required">
        (required)
      </span>

      <span class="error-message">
        Please choose one of the following options.
      </span>
      <select name="options" id="options" required=''>
        <option value=''> Select </option>
        <option value="value1">Option A</option>
        <option value="value2">Option B</option>
        <option value="value3">Option C</option>
      </select>
    </label>
  </fieldset>

  <button class='form-example-submit' type="submit">Submit Form</button>
</form>
1
2
3
4
5
6
7
input.edited:invalid {
  box-shadow: 0 0 5px 1px red;
}

input:focus:invalid {
  outline: none;
}

JavaScript validation with jQuery:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function handleFormSubmission(){
  $('.form-example input').on('keyup', function(e){
    $(this).addClass('edited');
  });

  $('.form-example [type="submit"]').on('click.formValidation', function(e){
    shouldPrevent = false;
    errorList = [];


    $form = $(this).parents('form');
    $inputs = $form.find('input[required], textarea[required], select[required]');

    $inputs.each(function(index, input){
      errorMessageSelector = 'label[for="' + $(input).attr('id') + '"] .error-message';
      $form.find(errorMessageSelector).removeAttr('aria-live');
      error = $form.find(errorMessageSelector);
      error.css('display', 'none');

      if(!input.validity.valid){
        error.css('display', 'inline-block');
        shouldPrevent = true;
        errorList.push(error);

      }
      else {
        error.css('display', 'none');
      }
    });

    if(!$form[0].checkValidity()){
      e.preventDefault();
      errorList[0].attr('aria-live', 'assertive');
    }
  });
}

$(document).ready(function(){
  handleFormSubmission();
});

Live Example

Personal Information
Credit Card Information
Can we add you to our email mailing list? (required)
Which topics interest you? (required)

CAPTCHAs

CAPTCHA forms are implemented to stop spammers and bots from submitting forms, but in doing so, they also deny some human users access.

CAPTCHAs are not blind-friendly, and are difficult for users with learning disabilities like dyslexia.

Consider an alternative method:

  • Logic questions: Use a question rather than an image or audio. A sample CAPTCHA question might be, “Which animal is larger, a mouse or a horse?” or “What state is Philadelphia located in?” You can also ask math questions, such as, “What is one plus three?” For high-volume sites, rotate questions, as hackers can develop algorithms to predict questions and answers or hire users to answer CAPTCHA questions. However, user with cognitive disabilities may still have trouble with this approach.

  • Moderators: For services with relatively light traffic, you can manually approve access or postings.

  • Spam detection: You could use natural language filters to detect spam messages, or watch for activity coming from similar IP addresses. Most major blogging or content management software contains spam filtering capabilities, or can be fitted with a plug-in for this functionality. Many of these filters can automatically delete messages that reach a certain spam threshold, and mark questionable messages for manual moderation.

  • Phone, text, or email verification: Email verification, where you acknowledge receipt of an email, is a common authentication technique that can be very accessible. Another way is telephone or SMS authentication.

Tools & Resources

Other Live Examples of Accessible Forms