Skip to Main Content
Mosaic Logo
Mosaic Logo
  • Home
  • Browse components
  • Use in projects
    • Colors
    • Icons
    • Grid
    • Links
    • Typography
    • Spacing Utilities
    • SVG
    • Accordions
    • Alerts
    • Badges
    • Buttons
    • Copy to clipboard
    • Cards
    • Featured Container
    • Filter Bar
    • Lists
    • Loading Spinners
    • Modals
    • Pagination
    • Progress Bars
    • Progress Indicator
    • Site Banner
    • Tables
    • Tabs
    • Toast
    • Toggle Switches
    • Well
    • Wizard
    • Events
    • File Browser
    • File Upload
    • Footer
    • Header
    • Hero
    • Post Item
    • Profile
    • Sidebar Navigation
    • Splash
    • Stack
    • Form Instructions
    • Form Layout
    • Form Validation
    • Form Output
    • Checkboxes
    • Labels
    • Radio Buttons
    • Search Input
    • Select
    • Text Inputs

Form Validation

To avoid users making errors during form submission keep the following in mind:

Built-in constraints on Inputs

Where appropriate, allow only certain kinds of input, such as only numerals when typing a zip code. To restrict the options even further, pre-define them as data values in <select> lists, radio buttons, checkboxes, or some other fixed format.

Step-by-Step views

When there are diverging paths through an interaction, it's usually not a good idea to show all possibilities at the same time. It can be confusing for users, and difficult in terms of the programming logic to ensure that all possibilities and error states are taken into account. Allow users to make a choice, then show the resulting set of choices for that path only.

Visual design that focuses user attention

Ensure labels and instructions are near their respective inputs. Reduce distractions in the visual design. Use visual cues to guide users to fill out the form properly. Make error messages and confirmation messages visually obvious.

Confirmation prior to submitting

Summarize what will happen when the user submits the form, BEFORE the form is submitted. Ask the user to verify that the information is correct. This is especially important when actions are irreversible.

Confirmation after submitting

Summarize the result on the screen after the form is submitted, to let users review their action once again.

Aim for inline validation whenever possible

Ideally, all validation should be inline: that is, as soon as the user has finished filling in a field, an indicator should appear nearby if the field contains an error. This type of error message is easily noticeable; moreover, fixing the error immediately after the field has been completed requires the least interaction cost for users: they don’t need to locate it or navigate to the field, nor do they have to switch context from a new field to return to an old field they thought they had completed successfully.

Of course, there will be situations where inline validation won’t be possible and data entered by the user will need to be sent to a server for verification.

Implementation Details

  • Set invalid fields to aria-invalid="true"
  • Move focus to error/success message
  • Ensure error/success message container is set to tabindex="-1". Otherwise, focus cannot be set successfully.
  • Provide a count of errors so that users get a sense of the scope of the problem.
  • Ensure error messages are associated with form fields using aria-describedby so that screen reader users know how to fix the problem
  • Ensure error messages are visible so that sighted users know how to fix the problems
  • Ensure error messages are adjacent to the inputs so that screen magnification users can easily see which messages belong to which fields.
Error Messaging

Use the .invlaid-feedback class to display error messages. You can toggle display properities to hide and show error messaging.

Please provide your first name.
Please provide your last name.
Please choose a username.
Please provide a valid city.
Please select a valid state.
Please provide a valid zip.
You must agree before submitting.

<form class="row g-4 needs-validation" novalidate>
  <div class="col-md-4">
    <label class="form-label" for="validationCustom01">First name</label>
    <input class="form-control" id="validationCustom01" type="text" required />
    <div class="invalid-feedback d-block">Please provide your first name.</div>
  </div>
  <div class="col-md-4">
    <label class="form-label" for="validationCustom02">Last name</label>
    <input class="form-control" id="validationCustom02" type="text" required />
    <div class="invalid-feedback d-block">Please provide your last name.</div>
  </div>
  <div class="col-md-4">
    <label class="form-label" for="validationCustomUsername">Username</label>
    <div class="input-group has-validation">
      <input
        class="form-control"
        id="validationCustomUsername"
        type="text"
        aria-describedby="inputGroupPrepend"
        required />
      <div class="invalid-feedback d-block">Please choose a username.</div>
    </div>
  </div>
  <div class="col-md-6">
    <label class="form-label" for="validationCustom03">City</label>
    <input class="form-control" id="validationCustom03" type="text" required />
    <div class="invalid-feedback d-block">Please provide a valid city.</div>
  </div>
  <div class="col-md-3">
    <label class="form-label" for="validationCustom04">State</label>
    <select class="form-select" id="validationCustom04" required>
      <option value="" selected disabled>Choose...</option>
      <option>...</option>
    </select>
    <div class="invalid-feedback d-block">Please select a valid state.</div>
  </div>
  <div class="col-md-3">
    <label class="form-label" for="validationCustom05">Zip</label>
    <input class="form-control" id="validationCustom05" type="text" required />
    <div class="invalid-feedback d-block d-block">
      Please provide a valid zip.
    </div>
  </div>
  <div class="col-12">
    <div class="form-check">
      <input
        class="form-check-input"
        id="invalidCheck"
        type="checkbox"
        value=""
        required />
      <label class="form-check-label" for="invalidCheck">
        Agree to terms and conditions</label
      >
      <div class="invalid-feedback d-block">
        You must agree before submitting.
      </div>
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>
Modal Error Message

Ensure that focus moves back to the first invalid form field when the modal is closed.

Error: There are 3 problems to fix in this form
  1. Name: You must provide a valid name. No numbers or symbols accepted.
  2. Zipcode: Please provide a valid US zipcode.
  3. Accept terms of use: Please check the box to agree to our user agreeement.

If the form submission causes a new page to load (or the same page to reload)

Ensure the page <title> reflects the error or success confirmation status.

The title could say something like, "There were 3 errors in the form" or "Success! Your account has been created." The page <title> is the first thing screen reader users hear when the page loads, so it is the fastest way to give them feedback on the form submission status.

Provide a quick way to reach the status message.

Some options include:

  • Provide a "skip to main content" link that takes the users to the message.
  • Move the focus to the confirmation message after the page loads.
    IMPORTANT: You will need to let the page finish loading, then set a JavaScript timeout of 1 to 2 seconds to allow the screen reader virtual buffer to process the page, then use JavaScript to send the focus to the confirmation message. If you send the focus to the message immediately upon page load, the focus may be set successfully, but screen readers will say nothing because they haven't had time to determine what is on the page.

References

  • Neilsen Norman Group
  • Deque
  • facebook

  • Instagram

  • Twitter

  • LinkedIn

  • YouTube

  • Accessibility
  • Privacy Policy
  • Contact Us
Sign up for our newsletter
ICPSR

© 2025 The Regents of the University of Michigan. ICPSR is part of the Institute for Social Research at the University of Michigan.