Forms

A form is a group of related input controls that allows users to provide data or configure options. Forms can be simple or complex, and may be presented as dedicated pages, side panels, or dialogs depending on the use case and the situation.

Table of Contents

Edit this section, Opens in new window

Overview

When to use

Forms are incredibly common in user interfaces and their design and usage continues to evolve as input methods get smarter and more and more people use mobile and tablet devices. You might design a form for a user to:

  • Sign up for / log into an account
  • Register for a service
  • Reconfigure settings, (e.g. enabling notifications)
  • Take a survey
  • Purchase a product
  • Provide feedback

Respect the user

Forms are meant to gather information and guide people with as little fuss as possible. To allow users to scan and complete the form quickly, forms should:

  • Respect the user’s GDPR and other privacy regulations by only asking for information that is absolutely necessary.
  • Group related tasks under section titles to provide more context and make the interface easier to scan.
  • Follow a logical, predictable order—e.g first name first, last name second.
  • Allow users to stay with a single interaction method for as long as possible (i.e. do not make users shift from keyboard to mouse numerous times in a single form).
  • When designing be mindful of password managers and browser capabilities that populate data for users.
  • Progressively disclose additional inputs only as they become relevant
Edit this section, Opens in new window

Style

Layout

TBD

Accessibility

When constructing a form, first refer to the specific accessibility guidance for each component used. Every text input should have a descriptive and visible label, along with hard coded instructions for input format. A form must be wrapped in a <form> element.

Requirements for your form should be announced and declared before the user enters the form.

The most significant challenge facing visually impaired users is form ordering. Your form should be tab-navigable, and required fields should be clearly labeled as such.

Validation messages should be included to advise the user of data that is input incorrectly or a required field that is missing information.

Helper text (label) should be used to provide instructions to help users understand how to complete the form fields as well as indicate any required and optional input, data formats, and other relevant information.

See the WCAG website for in-depth accessibility guidance for each form element.

Edit this section, Opens in new window

Validation

We want to make filling out web forms as easy as possible. So why do we insist on validating our forms? There are three main reasons:

  • We want to get the right data, in the right format. Our applications won't work properly if our users' data is stored in the wrong format, is incorrect, or is omitted altogether.
  • We want to protect our users' data. Forcing our users to enter secure passwords makes it easier to protect their account information.
  • We want to protect ourselves. There are many ways that malicious users can misuse unprotected forms to damage the application.

Warning: Never trust data passed to your server from the client. Even if your form is validating correctly and preventing malformed input on the client-side, a malicious user can still alter the network request.

Effective and immediate error messaging can help the user to understand the problem and how to fix it. First, inform the user what has happened, then provide guidance on next steps or possible resolutions. Always present error states on the form, and use inline errors whenever possible.

Client-side validation

We recommend validating the user’s data before form submission. This type of real-time, inline validation (a.k.a. client-side validation) should happen as soon as the field loses focus. This will help to easily identify the elements that need to be corrected.

The validation label below the field should be as informative as possible when describing the issue with the user’s data. For example, if password limitations require 16 characters, but the user inputs a password with only six characters, the text should read something like, "Password must be at least 16 characters."

Example

This example uses the Constraint validation API.

The html:

<form novalidate action="" class="if">
    <div class="if input-wrapper">
        <input
            data-size="larger"
            required
            placeholder="Enter your first name"
            name="first_name"
            id="first_name"
            type="text"
            minlength="2"
            class="if input-field"
        />
        <label class="if" for="first_name" aria-describedby="first_name_help-1 first_name_error-1"
            >First name*</label
        >
        <span class="if input-error" id="first_name_error-1" aria-live="polite"
            >A validation error</span
        >
        <span class="if input-help" id="first_name_help-1">A helpful text</span>
    </div>
    <div class="if input-wrapper">
        <button type="submit" id="submit" class="if primary button">Submit</button>
    </div>
</form>

This simple form uses the novalidate attribute to turn off the browser's automatic validation; this lets our script take control over validation. However, this doesn't disable support for the constraint validation API nor the application of CSS pseudo-classes like :valid, etc. That means that even though the browser doesn't automatically check the validity of the form before sending its data, you can still do it yourself and style the form accordingly.

Our input to validate is an <input type="text">, which is required, and has a minlength of 2 characters. Let's check these using our own code, and show a custom error message for each one.

Note: A key point here is that setting the novalidate attribute on the form is what stops the form from showing its own error message bubbles, and allows us to instead display the custom error messages in the DOM in some manner of our own choosing.

Now, let's look at the JavaScript:

const forms = document.querySelectorAll('form');
const isAllElementsValid = (els) => els.filter((el) => !el.validity.valid).length === 0;

forms.forEach((form) => {
    const formElements = Array.prototype.filter.call(
        form.elements,
        (el) => el.nodeName !== 'BUTTON'
    );

    formElements.forEach((el) => {
        el.addEventListener('blur', (e) => {
            if (el.validity.valid) {
                // In case there is an error message visible, if the field
                // is valid, we remove the error message.
                el.parentElement.querySelector('span.if.input-error').innerHTML = '';
                el.classList.remove('is-invalid');
                el.removeAttribute('aria-invalid');
            } else {
                // If there is still an error, show the correct error

                showError(el);
            }
        });
    });

    form.addEventListener('submit', (e) => {
        // if all fields are valid, we let the form submit

        if (!isAllElementsValid(formElements)) {
            // If it isn't, we display an appropriate error message
            showErrors(formElements);
            // Then we prevent the form from being sent by canceling the event
            event.preventDefault();
        } else {
            alert('valid');
        }
    });
});

const showErrors = (els) => {
    els.forEach((el) => {
        showError(el);
    });
};

Show error:

function showError(el) {
    const errorEl = el.parentElement.querySelector('span.if.input-error');
    if (el.validity.valueMissing && el.required) {
        // If the field is empty
        // display the following error message.
        // You can use the given el to extract label, name etc. to
        // provide more meaningful error messages
        errorEl.textContent = 'You need to enter something.';
        el.classList.add('is-invalid');
        el.setAttribute('aria-invalid', true);
    } else if (el.validity.typeMismatch) {
        // If the field doesn't contain the correct type
        // display the following error message.
        // You can use the given el to extract label, name etc. to
        // provide more meaningful error messages
        errorEl.textContent = 'Entered value needs to be an of correct type.';
        el.classList.add('is-invalid');
        el.setAttribute('aria-invalid', true);
    } else if (el.validity.badInput) {
        // If the field doesn't contain input the browser can't convert,
        // i.e. strings in a number field, we
        // display the following error message.
        // You can use the given el to extract label, name etc. to
        // provide more meaningful error messages
        errorEl.textContent = `Bad input, please enter a ${el.getAttribute('type')}.`;
        el.classList.add('is-invalid');
        el.setAttribute('aria-invalid', true);
    } else if (el.validity.tooShort) {
        // If the data is too short
        // display the following error message.
        // You can use the given el to extract label, name etc. to
        // provide more meaningful error messages
        errorEl.textContent = `Value should be at least ${el.minLength} characters; you entered ${el.value.length}.`;
        el.classList.add('is-invalid');
        el.setAttribute('aria-invalid', true);
    }
}

The comments explain things pretty well, but briefly:

  • Every time we change the value of the input, we check to see if it contains valid data. If it has then we remove any error message being shown. If the data is not valid, we run showError() to show the appropriate error.
  • Every time we try to submit the form, we again check to see if the data is valid. If so, we let the form submit. If not, we run showError() to show the appropriate error, and stop the form submitting with preventDefault().
  • The showError() function uses various properties of the input's validity object to determine what the error is, and then displays an error message as appropriate.

This code can also be seen and experienced on CodePen.

Server-side validation

TBD

Edit this section, Opens in new window

Anatomy

Forms are comprised of some or all of the following elements.

Personalia

Please fill out this form to receive a prize!

Please select an age range
For example: john.doe@gmail.com
Anatomy of a form
  1. Form headline
  2. Form description
  3. Input field
  4. Label
  5. Placeholder text
  6. An optional field
  7. Help tooltip
  8. Error message
  9. Required field
  10. Help text
  11. Button

Form headline

Form description

Input field

Please see the Input Fields documentation for more information about input fields.

Label

Effective form labeling helps users understand what information to enter into a form input. Using a placeholder text as a label is often applied as a space-saving method. However, this is not recommended because it hides context and presents accessibility issues.

Please see the Input Labels documentation for more information about input labels.

Text input

Data input

Selection controls

Radio buttons

Please see the Radio Button documentation for more information about Radio Buttons.

Checkboxes

Please see the Checkbox documentation for more information about checkboxes.

Toggle

Please see the Toggle documentation for more information about toggles.

Please see the Dropdown Select documentation for more information about dropdown selects.

Numeric Stepper

Please see the Numeric Stepper documentation for more information about numeric steppers.

Autocomplete

File upload

Placeholder text

Placeholder text provides hints or examples of what to enter (e.g. YYYY-MM-DD). Since placeholder text disappears once the user begins to input data, it should not contain crucial information. When the requested input may be unfamiliar to the user or formatting is in question, use placeholder text.

Do:

  • Keep hints as short as possible and never overrun the input field.
  • Properly anonymize examples rather than using real values.

Don't:

  • Use placeholder text to communicate complex and lengthy requirements like password requirements. Instead, use a help tooltip.
  • Provide placeholder text when it isn't necessary.
  • Ever use placeholder text as a replacement for field labels.

Help tooltip

Tooltips can be very useful for providing additional explanation to users that may be unfamiliar with a particular form field. They can also offer rationale for what may seem like an unusual request. However, research suggests that users should not have to dig around for a tooltip to access information that's essential for the completion of their task.

The help tooltip button is triggering a popover. Please see the Help Tooltip documentation for more information about Help Tooltip.

Vilket år blev/blir du ägare?

Do:

  • Use tooltips for explanatory or added information.
  • Tooltips are microcontent; keep them concise.

Don't:

  • Tooltips are not catchalls for content that doesn't fit elsewhere; they must be used intentionally and very sparingly.
  • Never house essential information in a tooltip.

Error message

An error message is displayed when the form or form element is invalid. The message should be short and simple, so that the user can act on it.

Use a valid SSN format: DDMMYY XXXXX
Vi behöver ditt personnummer för att kunna ge dig rätt pris. Personnummer ger oss uppgift om din ålder, var du bor och hur länge du har haft körkort.

If you are in need for a larger error text, you can use a red popover. NOTE: Use sparingly! There should not be many cases requiring long validation error messages.

For text fields that validate their content (such as passwords), replace helper text with error text when applicable. Swapping helper text with error text helps prevent new lines of text from being introduced into a layout, thus bumping content to fit it.

  • If only one error is possible, error text describes how to avoid the error
  • If multiple errors are possible, error text describes how to avoid the most likely error
A validation error
Swap helper text with error text.
A helper text A validation error
Don't place error text under helper text, as their appearance will shift content.
Long errors can wrap to multiple lines if there isn’t enough space to clearly describe the error. In this case, ensure padding between text fields is sufficient to prevent multi-lined errors from bumping layout content.
A validation error that should go over multiple lines
Long errors can wrap to multiple lines if there isn’t enough space to clearly describe the error. In this case, ensure padding between text fields is sufficient to prevent multi-lined errors from bumping layout content.

Help text

Help text appears below the input label and assists the user to provide the right information. Help text is always available, even when the field is focused, that's why it's the correct choice for need-to-know information. For context or background information that is "nice to have", use placeholder text or a tooltip.

Vilket år blev/blir du ägare?

Do:

  • Think of helper text as crucial information that is secondary to the input label.
  • Keep helper text as short and specific as possible.
  • Only use helper text when truly necessary to avoid overloading the user.

Don't:

  • Never use helper text in place of field labels.
  • Helper text should not run longer than the input area.

Button

Allows users to submit or exit a form.

Use a primary button for the main action, a secondary button for secondary actions like "Cancel" or "Discard".

Please see the button documentation for more information about buttons.

Edit this section, Opens in new window
Contact us, Opens in new window