Forms
- Form guidelines
- Text input fields
- Selections
- Dropdowns
- States
- Arrangement
- Field helpers
- Hints
- Example forms
Form guidelines
Keep forms as simple as possible
- Only ask for the information you absolutely need
- If you do ask for optional information, mark the labels of optional fields with ‘(optional)’
- Don’t mark mandatory fields with asterisks
Form fields
- Left-align labels, input fields, buttons and helper text
- Input boxes should invoke the appropriate mobile OS keyboard based on type
- Help prevent people from making errors; e.g. date pickers ensures correct date format
- Perform inline validation and provide clear error messages to resolve
Form focus states
- Interactive UI elements (buttons, links, menus, etc.) should have visible focus when swiped to / tapped
- Click on the label or inside the form field to show the focus state
- Focus should not get lost or reset to the top when interacting with UI elements
Text input fields
The simplest implementation of a form field consists of a .form
block containing a label and an input tag.
<fieldset class="field">
<label for="firstname">First Name</label>
<input id="firstname" name="firstname" required>
</fieldset>
<fieldset class="field">
<label for="comment">Message</label>
<textarea id="comment" name="comment" required></textarea>
</fieldset>
Disabling a field
Adding the standard [disabled]
HTML attribute will cause an input to appear greyed-out.
<fieldset class="field">
<label for="firstname">First Name (Disabled)</label>
<input id="firstname" name="firstname" disabled>
</fieldset>
Selections
A selection input allows a user to choose one, or many values from a set.
- The choices are grouped together by a
<fieldset>
tag - Each input should have its own
<label>
- The grouping is described as a whole by a
<legend>
or<h1>
tag within the fieldset
Radio inputs
A radio input lets the user pick a single value from one or more choices.
<fieldset class="field">
<legend class="heading-3">Choose one</legend>
<label for="choice_a" class="choice">
<input type="radio" name="answer" id="choice_a">
<span class="choice__text">Choice A</span>
</label>
<label for="choice_b" class="choice">
<input type="radio" name="answer" id="choice_b">
<span class="choice__text">Choice B</span>
</label>
<label for="choice_c" class="choice">
<input type="radio" name="answer" id="choice_c" disabled checked>
<span class="choice__text">Choice C</span>
</label>
</fieldset>
Checkboxes
Checkboxes are similar to radio buttons in their appearance and markup. The key difference is that checkboxes can accept a multiple choice response.
<fieldset class="field">
<legend class="heading-3">Choose all that apply</legend>
<label for="multiple-choice-a" class="choice">
<input type="checkbox" name="multiple-choice" id="multiple-choice-a">
<span class="choice__text">Choice A</span>
</label>
<label for="multiple-choice-b" class="choice">
<input type="checkbox" name="multiple-choice" id="multiple-choice-b">
<span class="choice__text">Choice B</span>
</label>
<label for="multiple-choice-c" class="choice">
<input type="checkbox" name="multiple-choice" id="multiple-choice-c" disabled>
<span class="choice__text">Choice C</span>
</label>
<label for="multiple-choice-d" class="choice">
<input type="checkbox" name="multiple-choice" id="multiple-choice-d" checked disabled>
<span class="choice__text">Choice D</span>
</label>
</fieldset>
Stand-alone selection
When only one choice is available, we can pare the field down to a simple .choice
block.
<label for="tos-agree" class="choice">
<input type="checkbox" id="tos-agree">
<span class="choice__text">I have read and agree to the Terms of Service</span>
</label>
Dropdowns
Create a dropdown by putting a label and select list inside the typical .field
block, and modifying .field__control
with --dropdown
.
<div class="field">
<label for="normal-dropdown">Dropdown Normal</label>
<div class="field__control field__control--dropdown">
<select id="normal-dropdown">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</select>
</div>
</div>
Disabled dropdown
Adding a [disabled]
attribute to the <select>
element will cause it to appear greyed out. In addition, modify .field__control
with --disabled
to correctly color the custom “caret” icon.
<div class="field">
<label for="disabled-dropdown">Dropdown Disabled</label>
<div class="field__control field__control--dropdown field__control--disabled">
<select id="disabled-dropdown" disabled>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</select>
</div>
</div>
States
Form states give the user feedback regarding their input. They can affirm that the user’s input was correct, or highlight errors that must be corrected.
- Modify the
.field
block with.field--success
when its input is correct. - When there’s a problem, use the
.field--error
modifier.
Accessibility
See Usable and Accessible Form Validation and Error Recovery by WebAIM for useful information on making form validation accessible. Some best practices for inline error recovery are:
- Associate the error message to the invalid control with
aria-describedby
- Apply
aria-invalid="true"
to the control - Set focus to the first control which needs attention
The Field Helpers section contains more documentation for inline error messages.
Text field states
Wrap the input element in a .field__control
block to ensure correct placement of the alert icon.
<div class="field field--success">
<label for="successful-field">Success state</label>
<div class="field__control">
<input type="text" id="successful-field">
</div>
</div>
<div class="field field--error">
<label for="error-field">Error state</label>
<div class="field__control">
<input type="text" id="error-field" aria-invalid="true">
</div>
</div>
Dropdown states
The .field
--success
and --error
modifiers will also style dropdowns with visual feedback.
<div class="field field--success">
<label for="success-dropdown">Dropdown Successful</label>
<div class="field__control field__control--dropdown">
<select id="success-dropdown">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</select>
</div>
</div>
<div class="field field--error">
<label for="error-dropdown">Dropdown error/message</label>
<div class="field__control field__control--dropdown">
<select id="error-dropdown" aria-invalid="true">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</select>
</div>
</div>
Selection field states
Use the .choice--error
modifier when there’s a problem with an individual choice of a selection field.
<fieldset class="field">
<legend class="heading-3">Which shape has less than ten sides?</legend>
<label for="choice-decagon" class="choice">
<input type="radio" id="choice-decagon" name="shape-choice">
<span class="choice__text">Decagon</span>
</label>
<label for="choice-octagon" class="choice choice--error">
<input type="radio" id="choice-octagon" name="shape-choice"
aria-invalid="true" aria-invalid="true">
<span class="choice__text">Octagon</span>
</label>
</fieldset>
<fieldset class="field">
<legend class="heading-3">Which shape has four or more sides?</legend>
<label for="choice-square" class="choice">
<input type="checkbox" id="choice-square" name="shape-choice" checked>
<span class="choice__text">Square</span>
</label>
<label for="choice-triangle" class="choice choice--error">
<input type="checkbox" id="choice-triangle" name="shape-choice"
aria-invalid="true" checked>
<span class="choice__text">Triangle</span>
</label>
</fieldset>
Arrangement
The responsive grid can be used to arrange complex form layouts.
<div class="grid-row">
<div class="medium-6">
<fieldset class="field">
<label for="input_a">Input A</label>
<input type="text" name="input_a">
</fieldset>
</div>
<div class="medium-6">
<fieldset class="field">
<label for="input_b">Input B</label>
<input type="text" name="input_b">
</fieldset>
</div>
</div>
<div class="grid-row">
<div class="xs-12">
<fieldset class="field">
<label for="input_c">Input C</label>
<input type="text" name="input_c">
</fieldset>
</div>
</div>
Size and spacing
The .button-row
block can be used to achieve the correct spacing between a form and its buttons. The class can be used on a stand-alone block, or mixed with .grid-row
.
When laying out fields that’ll potentially fill the entire viewport, the responsive grid should be used to constrain their maximum width to these limits:
- Small & XS: 12 columns
- Medium: 7 columns
- Large: 5 columns
- XL: 4 columns
These limits can be achieved by combining grid column helpers (.medium-7.large-5.xl-4
) or with the block .field-col
<div class="grid-row">
<div class="field-col">
<fieldset class="field">
<label for="query">What are you looking for?</label>
<input type="text" id="query" placeholder="Smart phones">
</fieldset>
</div>
</div>
<div class="button-row">
<button type="submit" class="button button--primary">
Search
</button>
</div>
Field helpers
A field helper offers the user a detailed explanation of the input expected by a form field. Construct one by placing a .helper
block between the label and input.
Use aria-describedby
to accessibly mark up the relationship between the input field and the helper text.
- Assign the helper block a unique
id
attribute. - Add an
aria-describedby
attribute to the input element. - Make the helper’s id the value of
aria-describedby
.
Standard field helper
Your password must be:
- 8 characters or longer, no spaces
- A mix of numbers, lowercase and uppercase letters
<div class="field">
<label for="input_d">Field helper</label>
<div class="helper" id="a-standard-helper">
<p class="text--medium">
<strong>Your password must be:</strong>
</p>
<ul class="list list--compact">
<li class="list__item">8 characters or longer, no spaces</li>
<li class="list__item">A mix of numbers, lowercase and uppercase letters</li>
</ul>
</div>
<input type="password" id="input_d" placeholder="Enter password"
aria-describedby="a-standard-helper">
</div>
Success modifier
The --success
modifier can be used on the helper to provide positive feedback when the user has successfully completed the form field.
Your password must be:
- 8 characters or longer, no spaces
- A mix of numbers, lowercase and uppercase letters
<div class="field field--success">
<label for="input_e">Successful field helper</label>
<div class="helper helper--success" id="a-success-helper">
<p class="text--medium">
<strong>Your password must be:</strong>
</p>
<ul class="list list--checked list--compact">
<li class="list__item">8 characters or longer, no spaces</li>
<li class="list__item">A mix of numbers, lowercase and uppercase letters</li>
</ul>
</div>
<input type="password" id="input_e" placeholder="Enter password"
aria-describedby="a-success-helper">
</div>
Error modifier
A helper modified with .helper--error
can give detailed instructions regarding why a form field could not be processed.
- The form control should be associated to the error message with
aria-describedby
- The
aria-invalid="true"
attribute should be added to the form control
<div class="field field--error">
<label for="omitted-field">Error state/message</label>
<div class="helper helper--error" id="omitted-field-error">
<strong>General or field specific error message.</strong>
</div>
<div class="field__control">
<input type="text" id="omitted-field" placeholder="Text"
aria-describedby="omitted-field-error" aria-invalid="true">
</div>
</div>
Use the “Error List” block when a field has a complex error message.
Your password must be:
- 8 characters or longer, no spaces
- A mix of numbers, lowercase and uppercase letters
<div class="field field--error">
<label for="input_f">Error field helper</label>
<div class="helper helper--error" id="unfortunate-error">
<p class="text--medium">
<strong>Your password must be:</strong>
</p>
<ul class="list list--error list--compact">
<li class="list__item">
8 characters or longer, no spaces
</li>
<li class="list__item">
A mix of numbers, lowercase and uppercase letters
</li>
</ul>
</div>
<div class="field__control">
<input type="password" id="input_f" placeholder="Enter password"
aria-describedby="unfortunate-error" aria-invalid="true">
</div>
</div>
Hints
Hints provide information a user may need to complete a form field. While a label is the succint, essential text identifying the purpose of an input field, a hint can be used to provide more detailed instructions.
- A hinted input should have an
aria-describedby
attribute whose value is theid
of the hint text. - The hint should not be nested inside the
<label>
tag. - Modify the
.field
block with.field--hinted
to position the icon correctly relative to the label. - Modify the
.hint
block with.hint--active
to reveal the speech bubble. - Toggle the text’s
aria-hidden
attribute when the button hides or shows the tooltip.
<div id="example-hint" class="field field--hinted">
<label for="hinted-field">Interactive hint</label>
<input type="text" id="hinted-field" aria-describedby="some-hint">
<div class="hint hint--active">
<button class="button-plain hint__trigger" aria-controls="some-hint">
<span class="accessible-hide">Toggle helper text visibility</span>
</button>
<span id="some-hint" class="hint__text" aria-role="tooltip" aria-hidden="false">
This text describes the field.
</span>
</div>
</div>
Example forms
See these features in action on the form examples page