Forms
updated

  • HTML/CSS Available
  • Web Component Available
  • Last Updated

    2.26.0

Forms gather information from users via Checkboxes, Inputs, Radio Buttons, Selects and Textareas. Labels sit atop these elements.

Elements

Form Wrappers

Form wrappers always enclose all form elements.

Form Wrapper
Form Wrapper
First Name
HTML Web Component
<form class="mds-form mds-form--medium-layout">
    <div class="mds-form__field-group">
        <label class="mds-form__label" for="input-01">
            First Name
        </label>
        <input class="mds-form__input" type="text" id="input-01">
    </div>
</form>
<form class="mds-form mds-form--medium-layout">
    <mds-field-group>
        <mds-label for="input-01">First Name</mds-label>
        <mds-input id="input-01"></mds-input>
    </mds-field-group>
</form>
  • Always use semantic HTML form elements, e.g., <fieldset>, <legend>, <label>, and <input> within form wrappers.

Spacing Elements

By default, form elements do not include any margins. To assist with the composition of many individual form elements in a complete form, MDS provides layout modifier classes which automatically apply margin-based spacing to all elements contained within a form.

Form layout modifier classes are available for all three sizes of form elements, mds-form--small-layout, mds-form--medium-layout, and mds-form--large-layout. Always apply these modifier classes to the block level of a <form> element, for example:

Example Form Spacing
Use the email address associated with your account.
Example Form Spacing
First Name Last Name Email Please use the Email address associated with your use account.
HTML Web Component
<form class="mds-form mds-form--large-layout">
    <div class="mds-form__field-group">
        <label class="mds-form__label mds-form__label--large" for="first-name">
            First Name
        </label>
        <input class="mds-form__input mds-form__input--large" type="text" id="first-name">
    </div>
    <div class="mds-form__field-group">
        <label class="mds-form__label mds-form__label--large" for="last-name">
            Last Name
        </label>
        <input class="mds-form__input mds-form__input--large" type="text" id="last-name">
    </div>
    <div class="mds-form__field-group">
        <label class="mds-form__label mds-form__label--large" for="email">
            Email
        </label>
        <span class="mds-form__microcopy mds-form__microcopy--large" id="email-microcopy">
            Use the email address associated with your account.
        </span>
        <input class="mds-form__input mds-form__input--large" type="text" id="email" aria-describedby="email-microcopy">
    </div>
</form>
<form class="mds-form mds-form--large-layout">
    <mds-field-group>
        <mds-label for="first-name" size="large">First Name</mds-label>
        <mds-input id="first-name" size="large"></mds-input>
    </mds-field-group>
    <mds-field-group>
        <mds-label for="last-name" size="large">Last Name</mds-label>
        <mds-input id="last-name" size="large"></mds-input>
    </mds-field-group>
    <mds-field-group>
        <mds-label for="email" size=large>Email</mds-label>
        <mds-microcopy id="email-microcopy" size="large">Please use the Email address associated with your use account.</mds-microcopy>
        <mds-input aria-describedby="email-microcopy" id="email" size="large"></mds-input>
    </mds-field-group>
</form>
  • Layout modifier classes only apply spacing to elements, you must still apply sizing modifier classes or props to each individual element within the form.
  • Always use form elements of the same size as the layout modifier class used to avoid undesirable spacing.

Field Groups

Field groups always wrap related elements.

Field Group
Microcopy Text Error Text
Field Group
Label Text Microcopy Text Error Text Label Text Label Text Label Text
HTML Web Component
<form class="mds-form mds-form--medium-layout">
    <div class="mds-form__field-group mds-form__field-group--error">
        <label class="mds-form__label" for="input-01">
            Label Text
        </label>
        <span class="mds-form__microcopy" id="input-01-microcopy">
            Microcopy Text
        </span>
        <input class="mds-form__input" type="text" id="input-01" aria-describedby="input-01-microcopy input-01-error">
        <span class="mds-form__field-error" id="input-01-error" role="alert">
            <span class="mds-form__field-error-text">
                Error Text
            </span>
        </span>
    </div>
    <div class="mds-form__field-group mds-form__field-group--horizontal">
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="input-02">
                Label Text
            </label>
            <input class="mds-form__input" type="text" id="input-02">
        </div>
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="input-03">
                Label Text
            </label>
            <input class="mds-form__input" type="text" id="input-03">
        </div>
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="input-04">
                Label Text
            </label>
            <input class="mds-form__input" type="text" id="input-04">
        </div>
    </div>
</form>
<form class="mds-form mds-form--medium-layout">
    <mds-field-group error>
        <mds-label for="input-01">Label Text</mds-label>
        <mds-microcopy id="input-01-microcopy">Microcopy Text</mds-microcopy>
        <mds-input aria-describedby="input-01-microcopy input-01-error" id="input-01"></mds-input>
        <mds-field-error id="input-01-error" visible>Error Text</mds-field-error>
    </mds-field-group>
    <mds-field-group horizontal>
        <mds-field-group>
            <mds-label for="input-02">Label Text</mds-label>
            <mds-input id="input-02"></mds-input>
        </mds-field-group>
        <mds-field-group>
            <mds-label for="input-03">Label Text</mds-label>
            <mds-input id="input-03"></mds-input>
        </mds-field-group>
        <mds-field-group>
            <mds-label for="input-04">Label Text</mds-label>
            <mds-input id="input-04"></mds-input>
        </mds-field-group>
    </mds-field-group>
</form>
  • If a form field includes Microcopy and/or a Field Error, always place these elements within the field group container wrapping the relevant field.
  • Multiple pieces of descriptive text, like Microcopy and a Field Error, can be linked to a single element by placing multiple id in an element's aria-describedby attribute. See accessibility guidelines for more information.
  • To create a horizontal group of form elements, wrap multiple field groups within a parent field group and apply the mds-form__field-group--horizontal modifier class or horizontal prop. This applies margin-right to elements contained within the child field group containers.

Field Sets

Field sets wrap multiple deeply related elements within a form, e.g., fields for entering an address. Always include a descriptive legend using mds-form__legend when using a field set.

Field Set
Address
Field Set
Address Address City State Zip Code
HTML Web Component
<form class="mds-form mds-form--medium-layout" method="post" action="form/processor">
    <fieldset class="mds-form__fieldset">
        <legend class="mds-form__legend">Address</legend>
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="full-form-address">
                Address
            </label>
            <input class="mds-form__input" type="text" id="full-form-address">
        </div>
        <div class="mds-form__field-group mds-form__field-group--horizontal">
            <div class="mds-form__field-group">
                <label class="mds-form__label" for="full-form-city">
                    City
                </label>
                <input class="mds-form__input" type="text" id="full-form-city">
            </div>
            <div class="mds-form__field-group">
                <label class="mds-form__label" for="full-form-state">
                    State
                </label>
                <div class="mds-form__select demo-width-100">
                    <select class="mds-form__select-input" id="full-form-state">
                        <option class="mds-form__select-option" value="default">Select your state</option>
                        <option class="mds-form__select-option" value="just">Just</option>
                        <option class="mds-form__select-option" value="kidding">Kidding</option>
                    </select>
                    <div class="mds-form__select-visual-wrap"></div>
                    <span class="mds-form__select-open-indicator">
                        <svg class="mds-icon mds-form__select-open-icon" aria-hidden="true">
                            <use xlink:href="#caret-down--s">
                            </use>
                        </svg>
                    </span>
                </div>
            </div>
            <div class="mds-form__field-group">
                <label class="mds-form__label" for="full-form-zip">
                    Zip Code
                </label>
                <input class="mds-form__input" type="text" id="full-form-zip">
            </div>
        </div>
    </fieldset>
</form>
<form class="mds-form mds-form--medium-layout">
    <fieldset class="mds-form__fieldset">
        <legend class="mds-form__legend">Address</legend>
        <mds-field-group>
            <mds-label for="full-form-address">Address</mds-label>
            <mds-input id="full-form-address">
                <mds-input>
        </mds-field-group>
        <mds-field-group horizontal>
            <mds-field-group>
                <mds-label for="full-form-city">City</mds-label>
                <mds-input id="full-form-city">
                    <mds-input>
            </mds-field-group>
            <mds-field-group>
                <mds-label for="full-form-state">State</mds-label>
                <mds-select additional-class="demo-width-100" id="full-form-state" placeholder="Select your state" options='[{"text": "Just", "value": "just"}, {"text": "Kidding", "value": "kidding"}]'>
                </mds-select>
            </mds-field-group>
            <mds-field-group>
                <mds-label for="full-form-zip">Zip Code</mds-label>
                <mds-input id="full-form-zip">
                    <mds-input>
            </mds-field-group>
        </mds-field-group>
    </fieldset>
</form>
  • mds-form__fieldset and mds-form__legend are non-visible elements that play a critical role in making forms accessible for those using assistive technologies, like screen readers. See accessibility guidelines for more information.
  • <fieldset> elements may be nested with another <fieldset>, for example, if using the Radio group or Checkbox group.

Examples

Address Form

This example combines many form elements wrapped with a mds-form--medium-layout modifier class to apply margin-based spacing. It uses a Required Fields Key, Labels (default and required), Inputs, Select, Textarea, and a Button.

Address Form
Address Required fields
Address Form
Address Required fields First Name Last Name Address City State Zip Code Comments
Submit
HTML Web Component
<form class="mds-form mds-form--medium-layout" method="post" action="form/processor">
    <fieldset class="mds-form__fieldset">
        <legend class="mds-form__legend">Address</legend>
        <span class="mds-form__required-fields-key">Required fields</span>
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="full-form-first-name">
                First Name
                <abbr class="mds-form__label-required-indicator" title="This field is required." aria-label="This field is required.">*</abbr>
            </label>
            <input class="mds-form__input" type="text" id="full-form-first-name">
        </div>
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="full-form-last-name">
                Last Name
                <abbr class="mds-form__label-required-indicator" title="This field is required." aria-label="This field is required.">*</abbr>
            </label>
            <input class="mds-form__input" type="text" id="full-form-last-name">
        </div>
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="full-form-address">
                Address
            </label>
            <input class="mds-form__input" type="text" id="full-form-adress">
        </div>
        <div class="mds-form__field-group mds-form__field-group--horizontal">
            <div class="mds-form__field-group">
                <label class="mds-form__label" for="full-form-city">
                    City
                </label>
                <input class="mds-form__input" type="text" id="full-form-city">
            </div>
            <div class="mds-form__field-group">
                <label class="mds-form__label" for="full-form-state">
                    State
                </label>
                <div class="mds-form__select demo-width-100">
                    <select class="mds-form__select-input" id="full-form-state">
                        <option class="mds-form__select-option" value="default">Select your state</option>
                        <option class="mds-form__select-option" value="just">Just</option>
                        <option class="mds-form__select-option" value="kidding">Kidding</option>
                    </select>
                    <div class="mds-form__select-visual-wrap"></div>
                    <span class="mds-form__select-open-indicator">
                        <svg class="mds-icon mds-form__select-open-icon" aria-hidden="true">
                            <use xlink:href="#caret-down--s">
                            </use>
                        </svg>
                    </span>
                </div>
            </div>
            <div class="mds-form__field-group">
                <label class="mds-form__label" for="full-form-zip">
                    Zip Code
                </label>
                <input class="mds-form__input" type="text" id="full-form-zip">
            </div>
        </div>
        <div class="mds-form__field-group">
            <label class="mds-form__label" for="full-form-comments">
                Comments
            </label>
            <textarea class="mds-form__textarea" id="full-form-comments"></textarea>
        </div>
    </fieldset>
    <div class="demo-button-container">
        <button class="mds-button mds-button--primary" type="button" disabled>
            Submit
        </button>
    </div>
</form>
<form class="mds-form mds-form--medium-layout" method="post" action="form/processor">
    <fieldset class="mds-form__fieldset">
        <legend class="mds-form__legend">Address</legend>
        <mds-required-fields-key>Required fields</mds-required-fields-key>
        <mds-field-group>
            <mds-label for="full-form-first-name" required>First Name</mds-label>
            <mds-input id="full-form-first-name"></mds-input>
        </mds-field-group>
        <mds-field-group>
            <mds-label for="full-form-last-name" required>Last Name</mds-label>
            <mds-input id="full-form-first-name"></mds-input>
        </mds-field-group>
        <mds-field-group>
            <mds-label for="full-form-address">Address</mds-label>
            <mds-input id="full-form-address"></mds-input>
        </mds-field-group>
        <mds-field-group horizontal>
            <mds-field-group>
                <mds-label for="full-form-city">City</mds-label>
                <mds-input id="full-form-city"></mds-input>
            </mds-field-group>
            <mds-field-group>
                <mds-label for="full-form-state">State</mds-label>
                <mds-select additional-class="demo-width-100" id="full-form-state" placeholder="Select your state" options='[{"text": "Just", "value": "just"}, {"text": "Kidding", "value": "kidding"}]'>
                </mds-select>
            </mds-field-group>
            <mds-field-group>
                <mds-label for="full-form-zip">Zip Code</mds-label>
                <mds-input id="full-form-zip"></mds-input>
            </mds-field-group>
        </mds-field-group>
        <mds-field-group>
            <mds-label for="full-form-comments">Comments</mds-label>
            <mds-textarea id="full-form-comments"></mds-textarea>
        </mds-field-group>
    </fieldset>
    <div class="demo-button-container">
        <mds-button variation="primary" disabled>Submit</mds-button>
    </div>
</form>

MDS Features

  • Uses the mds-form--medium-layout modifier class to apply medium form margins to all contained elements.
  • Uses either the mds-form__field-group--horizontal modifier class or the horizontal prop to create a horizontal group of inputs.

Customizations

Selects need a width: 100%; property applied to ensure they expand to fill their available space when placed within a field group using the mds-form__field-group--horizontal modifier class or the horizontal prop.

Sign Up Form

This example uses large form elements wrapped with a mds-form--large-layout modifier class to apply margin-based spacing. It uses a Required Fields Key, Labels (default, optional, and required), Inputs, Microcopy, Radio Group, and a Button.

Sign Up Form
Sign Up Required fields
Please provide your last name.
We’ll never share your email with third parties.
Would you like to sign up for our newsletter? We won’t send you more than one email a week.
Sign Up Form
Sign Up Required fields First Name Last Name Please provide your last name. Email We’ll never share your email with third parties. We won’t send you more than one email a week. Yes, please. No, thanks.
Sign Up
HTML Web Component
<form class="mds-form mds-form--large-layout" method="post" action="form/processor">
    <fieldset class="mds-form__fieldset">
        <legend class="mds-form__legend">Sign Up</legend>
        <span class="mds-form__required-fields-key mds-form__required-fields-key--large">Required fields</span>
        <div class="mds-form__field-group">
            <label class="mds-form__label mds-form__label--large" for="full-form-first-name">
                First Name
                <abbr class="mds-form__label-required-indicator" title="This field is required." aria-label="This field is required.">*</abbr>
            </label>
            <input class="mds-form__input mds-form__input--large" type="text" id="full-form-first-name">
        </div>
        <div class="mds-form__field-group mds-form__field-group--error">
            <label class="mds-form__label mds-form__label--large" for="full-form-last-name">
                Last Name
                <abbr class="mds-form__label-required-indicator" title="This field is required." aria-label="This field is required.">*</abbr>
            </label>
            <input class="mds-form__input mds-form__input--large" type="text" id="full-form-last-name" aria-describedby="full-form-last-name__error">
            <span class="mds-form__field-error mds-form__field-error--large" id="full-form-last-name__error" role="alert">
                <span class="mds-form__field-error-text">
                    Please provide your last name.
                </span>
            </span>
        </div>
        <div class="mds-form__field-group">
            <label class="mds-form__label mds-form__label--large" for="full-form-email__input">
                Email<span class="mds-form__label-optional">
                    (Optional)
                </span>
            </label>
            <span class="mds-form__microcopy mds-form__microcopy--large" id="full-form-email__microcopy">
                We’ll never share your email with third parties.
            </span>
            <input class="mds-form__input mds-form__input--large" type="text" id="full-form-email__input" aria-describedby="full-form-email__microcopy">
        </div>
        <div class="mds-form__field-group">
            <fieldset class="mds-form__radio-button-group mds-form__radio-button-group--large" role="radiogroup">
                <legend class="mds-form__radio-button-group-label">
                    Would you like to sign up for our newsletter?
                </legend>
                <span class="mds-form__microcopy mds-form__microcopy--large" id="full-form-newsletter__microcopy">
                    We won’t send you more than one email a week.
                </span>
                <label class="mds-form__radio-button mds-form__radio-button--large" for="yes,-please.--20848">
                    <input id="yes,-please.--20848" name="undefined-newsletter" value="blue" type="radio" class="mds-form__radio-button-input" checked aria-describedby="full-form-newsletter__microcopy" />
                    <span class="mds-form__radio-button-visible-wrap">
                        <span class="mds-form__radio-button-visual"></span>
                        <span class="mds-form__radio-button-text ">
                            Yes, please.
                        </span>
                    </span>
                </label>
                <label class="mds-form__radio-button mds-form__radio-button--large" for="no,-thanks.--80654">
                    <input id="no,-thanks.--80654" name="undefined-newsletter" value="blue" type="radio" class="mds-form__radio-button-input" aria-describedby="full-form-newsletter__microcopy" />
                    <span class="mds-form__radio-button-visible-wrap">
                        <span class="mds-form__radio-button-visual"></span>
                        <span class="mds-form__radio-button-text ">
                            No, thanks.
                        </span>
                    </span>
                </label>
            </fieldset>
        </div>
    </fieldset>
    <div class="demo-button-container">
        <button class="mds-button mds-button--primary mds-button--large" type="button" disabled>
            Sign Up
        </button>
    </div>
</form>
<form class="mds-form mds-form--large-layout" method="post" action="form/processor">
    <fieldset class="mds-form__fieldset">
        <legend class="mds-form__legend">Sign Up</legend>
        <mds-required-fields-key size="large">Required fields</mds-required-fields-key>
        <mds-field-group>
            <mds-label for="full-form-first-name" size="large" required>First Name</mds-label>
            <mds-input id="full-form-first-name" size="large"></mds-input>
        </mds-field-group>
        <mds-field-group error>
            <mds-label for="full-form-last-name" size="large" required>Last Name</mds-label>
            <mds-input aria-describedby="full-form-last-name__error" id="full-form-first-name" size="large"></mds-input>
            <mds-field-error id="full-form-last-name__error" size="large" visible>Please provide your last name.</mds-field-error>
        </mds-field-group>
        <mds-field-group>
            <mds-label for="full-form-email__microcopy" size="large" optional>Email</mds-label>
            <mds-microcopy id="full-form-email__microcopy" size="large">We’ll never share your email with third parties.</mds-microcopy>
            <mds-input aria-describedby="full-form-email__microcopy" id="full-form-address" size="large">
                <mds-input>
        </mds-field-group>
        <mds-field-group>
            <mds-radio-button-group size="large" label="Would you like to sign up for our newsletter?">
                <mds-microcopy id="full-form-newsletter__microcopy" size="large">We won’t send you more than one email a week.</mds-microcopy>
                <mds-radio-button aria-describedby="full-form-newsletter__microcopy" name="radio-group-example" size="large" value="yes" checked> Yes, please. </mds-radio-button>
                <mds-radio-button aria-describedby="full-form-newsletter__microcopy" name="radio-group-example" size="large" value="no"> No, thanks. </mds-radio-button>
            </mds-radio-button-group>
        </mds-field-group>
    </fieldset>
    <div class="demo-button-container">
        <mds-button size="large" variation="primary" disabled>Sign Up</mds-button>
    </div>
</form>

MDS Features

  • Uses the mds-form--large-layout modifier class to apply large form margins to all contained elements.
  • Uses the --large modifier classes or the large prop values on all form elements to render their large sizes.

CSS

Class References

Class
Applies to
Outcome

mds-form--small-layout

mds-form

Applies margin-based spacing to all contained form elements.

mds-form--medium-layout

mds-form

Applies margin-based spacing to all contained form elements.

mds-form--large-layout

mds-form

Applies margin-based spacing to all contained form elements.

mds-form__field-group--horizontal

mds-form__field-group

Changes the layout of form fields from vertical to horizontal.

mds-form__field-group--error

mds-form__field-group

Applies error styles to form elements.

Mixins

All Form Touch Properties

Use this mixin to create media queries in your product styles to switch all form elements to their touch variation. Includes styles for:

@include mds-form-all-touch-properties();

For example, switching to the touch variation on screens with a max-width of 500px:

// Your product SCSS
@media screen and (max-width: 500px) {
    @include mds-form-all-touch-properties();
}
  • The mixin includes all CSS properties required to convert any size into the touch variation. See mixin documentation on individual component pages for more information.
  • Use a media query that makes the most sense for your product, in addition to max-width, pointer: coarse is another helpful method for targeting touch screen devices.

Web Component

Field Group

Props

When setting props as attributes on a custom HTML element, use kebab-case instead of camelCase.

Prop
Type
Validation
Default
Description

additionalClass

String

A space-separated list of class names that will be appended to the default mds-card class.

error

Boolean

false

Deprecated, will be removed in v3.0. See Additional Behaviors section. Applies error styles to form elements. Avoid setting this prop manually, see Additional Behaviors below for more information.

horizontal

Boolean

Only applies to <mds-radio-button-group>, <mds-checkbox-group> and other <mds-field-group>

false

Changes the layout of form fields from vertical to horizontal.

Slots

Default Slot

Pass two or more Form elements (Checkboxes, Field Errors, Inputs, Labels, Microcopy, Radio Buttons, Selects, or Textareas) between the <mds-field-group></mds-field-group> tags to set the content of the field group.

Additional Behaviors

Field Error Event Listener

Field groups automatically synchronize error states across child elements by listening for events triggered by a child Field Error’s show() and hide() methods.

  • When a Field Error emits the mds-field-error-activated event, the parent field group’s error prop is set to true. Inversely, when the Field Error emits the mds-field-error-dismissed event, the parent field group’s error prop is set to false.
  • When the field group’s error prop is true, the form element within the field group—for example, an Input—will automatically switch to its visual error state (with the red underline).

Usage Examples

Using the default slot for contained form elements:

<form class="mds-form mds-form--medium-layout">
    <mds-field-group>
        <mds-label for="first-name">First Name</mds-label>
        <mds-input placeholder="First Name" id="first-name"></mds-input>
        <mds-field-error id="first-name-error">Please provide your first name.</mds-field-error>
    </mds-field-group>
</form>

Implementation

  • Always include a label with each form element.
  • Include a for attribute on each label with a value matching the id attribute on the corresponding Input, Textarea, or Select.
  • Use placeholder text to provide an example of the type of input you need from the user. For example, if you need a phone number in a certain format, include (123) 456-7890 as placeholder text.
  • Include an aria-describedby attribute on each Input, Textarea, or Select that has a Microcopy or a Field Error providing additional information. The value of the aria-describedby attribute must match the id attribute on the Microcopy or Field Error.
  • Always include role="alert" on Field Error components.
  • Every form element needs a visible Label.
  • Add aria-invalid="true" to an element where a validation error has occurred.
  • Use fieldset and legend for grouped form elements, such as Radio Buttons and Checkboxes.

Best Practices

  • Ensure all form elements are keyboard accessible.
  • Never use placeholder text in place of a label.