About
Stylable form inputs with validation
variants: inline / aligned layout.
Randon user names, details and email address lengths - good to add/test with randomuser.me
Test and save a range of different input types
o-form__control contains the label, alert and input.
If there is a group of inputs (eg, radio or checkboxes), we can still utilise the control, adding a form group around the inputs, all contained within the control (label elements will need to be changed to div, and each grouped input label have it’s element changed to a label).
Multiple controls can be laid out by it’s parent container (using css grid).
Don’t use a placeholder by utilising easily accessible text under the label, before the input.
Alternatives
Accessibility
There may be more a11y to add or something better.
Best a11y recommendation is to have label above hint above input above validation error message - Adrian Roselli and Scott Vinkle (Shopify) says the error message (o-form__alert) should be below the input so that if the user has zoomed in, and are taken to the (focussed) input they can still see the errror message below the input.
Or conflicting opinion: below the label and hint, but above input.
Requirements
Issues
Examples
Buttons
Simple form
If there is a c-label-hint (must have an ID), then also need to append aria-describedby="hint-ID" directly to the input.
With Error state
Input with button
Single input with adjacent button
this won’t align with a label above input
Aligned input with button
this aligns even with a label above each input, except error message
Multiple inputs with adjacent button
Accessible Search Reveal
This works with keyboard, touch and mouse. But doesn’t have a no-js fallback and will need to add option to the expandsion area to be position absolute to go above other elements (eg, Nav/logo). Needs converting to Angular JS.
Based on Adrian Roselli’s accessibility work.
Newsletter sign-up form (‘inline’)
A form with multiple sections and input groups
It makes sense to use a fieldset to group multiple related inputs. A legend is required to describe the set of fields, and we can use a heading inside a legend.
Code for above examples
<form action="#formsubmit" class="o-form" id="form_id_1" method="post" name="form_id_1">
<div class="o-form__row">
<div class="o-form__control">
<div class="o-form__label">
<label for="inputid1" class="c-label">
<span class="c-label__text">Full Name</span>
</label>
<div class="c-label-hint" id="inputid1_hint">Optional extra label text</div>
</div>
<div class="o-form__input">
<span class="c-input">
<input id="inputid1" class="c-input__field" name="Name" type="text" value="" aria-describedby="inputid1_hint" />
</span>
</div>
<div class="o-form__alert-inline"></div>
</div>
</div>
<div class="o-form__row o-form__row--actions">
<div class="o-form__control">
<button type="submit" class="c-button c-button--secondary">
<span class="c-button__body">
<span class="c-button__text">Send</span>
</span>
</button>
</div>
</div>
</form><form id="form_id_5" class="o-form o-search">
<div id="search" role="search" class="c-search">
<div class="o-form__row o-form__row--expand">
<div class="o-form__control o-form__control--label">
<label for="s1" class="o-form__label" aria-label="Search for:">
<svg class="c-icon c-icon--open" role="image" focusable="false">
<g aria-labeledby="title-search" aria-describedby="desc-search">
<title id="title-search">Search:</title>
<desc id="desc-search">Type some text to perform a search.</desc>
<use xlink:href="/assets/icons/symbols.svg#icon--search"></use>
</g>
</svg>
</label>
</div>
<div class="o-form__control o-form__control--input">
<div class="o-form__input">
<span class="c-input c-input--text">
<input id="s1" class="c-input__field" name="s1" type="text" value="" placeholder="Search…" />
</span>
</div>
</div>
<div class="o-form__control o-form__control--actions">
<button type="submit" class="c-button c-button--inline" aria-label="Perform search.">
<svg class="c-icon c-icon--search" role="image" focusable="false">
<g aria-labeledby="title-search-line" aria-describedby="desc-search-line">
<title id="title-search-line">Perform search.</title>
<desc id="desc-search-line">Submit your search term(s).</desc>
<use xlink:href="/assets/icons/symbols.svg#icon--search"></use>
</g>
</svg>
</button>
</div>
</div>
</div>
</form><form action="/contact" class="o-form" id="f1-form-signup" method="post" name="formNewsletter">
<div class="o-form__error-summary c-error-summary" aria-labelledby="f1-error-summary-title" role="alert" tabindex="-1">
<h3 class="c-error-summary__title" id="f1-error-summary-title">
There is a problem
</h3>
<div class="c-error-summary__body">
<ul class="o-l o-l--form-error-summary">
<li class="o-l__item">
<a href="#f1-newsletter-signup-lastname">Enter a last name</a>
</li>
<li class="o-l__item">
<a href="#f1-newsletter-signup-email">Enter an email address</a>
</li>
<li class="o-l__item">
<a href="#f1-newsletter-signup-region">Choose a region</a>
</li>
</ul>
</div>
</div>
<div class="o-form__row o-form__row--grid o-form__row--md-1-2">
<div class="o-form__control">
<div class="o-form__label">
<label for="f1-newsletter-signup-firstname" class="c-label">First Name</label>
</div>
<div class="o-form__input">
<span class="c-input">
<input class="c-input__field" id="f1-newsletter-signup-firstname" name="FirstName" type="text" value="" />
</span>
</div>
</div>
<div class="o-form__control">
<div class="o-form__label">
<label for="f1-newsletter-signup-lastname" class="c-label">Last Name</label>
</div>
<div class="o-form__input">
<span class="c-input c-input--error">
<input class="c-input__field" id="f1-newsletter-signup-lastname" name="LastName" type="text" value="" />
</span>
</div>
<div class="o-form__alert">
<span class="o-form__alert-content">Please enter your surname</span>
</div>
</div>
<div class="o-form__control">
<div class="o-form__label">
<label for="f1-newsletter-signup-email" class="c-label">Email Address</label>
</div>
<div class="o-form__input">
<span class="c-input c-input--error">
<input class="c-input__field c-input__field--" id="f1-newsletter-signup-email" name="Email" type="email" value="" />
</span>
</div>
<div class="o-form__alert">
<span class="o-form__alert-content">Your email address appears to be missing an @ symbol verbose comment</span>
</div>
</div>
<div class="o-form__control">
<div class="o-form__label">
<label for="f1-newsletter-signup-region" class="c-label">Region</label>
<div class="c-label-hint">Optional extra label text (date format eg, 27/03/2019) </div>
</div>
<div class="o-form__input">
<span class="c-input c-input--select">
<select class="c-input__field c-input__field--select" id="f1-newsletter-signup-region" name="Region">
<option disabled="disabled" selected="selected" value="">Please select a region</option>
<option value="london">London</option>
<option value="midlands">Midlands</option>
<option value="northwest">North West</option>
<option value="scotland">Scotland</option>
<option value="south">South</option>
<option value="southwest">South West & Wales</option>
<option value="northeast">Yorkshire & North East</option>
<option value="international">International</option>
</select>
</span>
</div>
<div class="o-form__alert">
<span class="o-form__alert-content">Please choose a region</span>
</div>
</div>
</div>
<div class="o-form__row o-form__row--actions">
<div class="o-form__actions">
<button class="c-button c-button--secondary" type="submit">
<span class="c-button__body">
<span class="c-button__text">
<span>Sign up</span>
</span>
</span>
</button>
</div>
</div>
</form><form action="/contact" class="o-form" id="f2-form-signup" method="post" name="formNewsletter">
<div class="o-form__error-summary c-error-summary" aria-labelledby="f2-error-summary-title" role="alert" tabindex="-1">
<h3 class="c-error-summary__title" id="f2-error-summary-title">
There is a problem
</h3>
<div class="c-error-summary__body">
<ul class="o-l o-l--form-error-summary">
<li class="o-l__item">
<a href="#address-line1">Enter the first line of your delivery address</a>
</li>
<li class="o-l__item">
<a href="#postcode">Enter a postcode, like AA1 1AA</a>
</li>
</ul>
</div>
</div>
<div class="o-form__row">
<fieldset class="o-fieldset" aria-describedby="f2-fieldset-radio-hint">
<legend class="o-fieldset__legend">
<h3 class="o-fieldset__heading">Fieldset of radio options</h3>
</legend>
<div class="c-label-hint" id="f2-fieldset-radio-hint">Extra 'label' text (should provide a hint to completing the input)</div>
<div class="o-form__input o-form__input--group">
<label class="c-input c-input--radio">
<input type="radio" name="radioinput" value="radio-value-1" class="c-input__field vh">
<svg class="c-icon c-icon--radio" aria-hidden="true" focusable="false">
<use class="c-icon--unchecked" xlink:href="/assets/icons/symbols.svg#icon--radio-unchecked"></use>
<use class="c-icon--checked" xlink:href="/assets/icons/symbols.svg#icon--radio-checked"></use>
</svg>
<span class="c-input__label">Label for radio 1</span>
</label>
<label class="c-input c-input--radio">
<input type="radio" name="radioinput" value="radio-value-2" class="c-input__field vh">
<svg class="c-icon c-icon--radio" aria-hidden="true" focusable="false">
<use class="c-icon--unchecked" xlink:href="/assets/icons/symbols.svg#icon--radio-unchecked"></use>
<use class="c-icon--checked" xlink:href="/assets/icons/symbols.svg#icon--radio-checked"></use>
</svg>
<span class="c-input__label">Label for radio 2</span>
</label>
<label class="c-input c-input--radio">
<input type="radio" name="radioinput" value="radio-value-3" class="c-input__field vh">
<svg class="c-icon c-icon--radio" aria-hidden="true" focusable="false">
<use class="c-icon--unchecked" xlink:href="/assets/icons/symbols.svg#icon--radio-unchecked"></use>
<use class="c-icon--checked" xlink:href="/assets/icons/symbols.svg#icon--radio-checked"></use>
</svg>
<span class="c-input__label">Label for radio 3</span>
</label>
</div>
</fieldset>
</div>
<div class="o-form__row">
<fieldset class="o-fieldset" aria-describedby="f2-fieldset-checkboxes-hint">
<legend class="o-fieldset__legend">
<h3 class="o-fieldset__heading">Fieldset of checkbox options</h3>
</legend>
<div class="c-label-hint" id="f2-fieldset-checkboxes-hint">Extra 'label' text (should provide a hint to completing the input), choose one or more options</div>
<div class="o-form__input o-form__input--group o-form__input--vertical">
<label for="checkboxinput-1" class="c-input c-input--checkbox">
<input type="checkbox" id="checkboxinput-1" name="checkboxinput-1" value="checkbox-value-1" class="c-input__field vh">
<svg class="c-icon c-icon--checkbox" aria-hidden="true" focusable="false">
<use class="c-icon--unchecked" xlink:href="/assets/icons/symbols.svg#icon--checkbox-unchecked"></use>
<use class="c-icon--checked" xlink:href="/assets/icons/symbols.svg#icon--checkbox-checked"></use>
</svg>
<span class="c-input__label">Label for checkbox</span>
</label>
<label for="checkboxinput-2" class="c-input c-input--checkbox">
<input type="checkbox" id="checkboxinput-2" name="checkboxinput-2" value="checkbox-value-2" class="c-input__field vh">
<svg class="c-icon c-icon--checkbox" aria-hidden="true" focusable="false">
<use class="c-icon--unchecked" xlink:href="/assets/icons/symbols.svg#icon--checkbox-unchecked"></use>
<use class="c-icon--checked" xlink:href="/assets/icons/symbols.svg#icon--checkbox-checked"></use>
</svg>
<span class="c-input__label">Label for checkbox</span>
</label>
<label for="checkboxinput-3" class="c-input c-input--checkbox">
<input type="checkbox" id="checkboxinput-3" name="checkboxinput-3" value="checkbox-value-3" class="c-input__field vh">
<svg class="c-icon c-icon--checkbox" aria-hidden="true" focusable="false">
<use class="c-icon--unchecked" xlink:href="/assets/icons/symbols.svg#icon--checkbox-unchecked"></use>
<use class="c-icon--checked" xlink:href="/assets/icons/symbols.svg#icon--checkbox-checked"></use>
</svg>
<span class="c-input__label">Label for checkbox</span>
</label>
</div>
<div class="o-form__alert">
<span class="o-form__alert-content">Please choose at least one label</span>
</div>
</fieldset>
</div>
<div class="o-form__row">
<div class="o-form__control">
<div class="o-form__label">
<label class="c-label" for="f2-thething-textarea">
<span class="c-label__text">Can you provide more detail?</span>
</label>
<div id="f2-thething-textarea-hint" class="c-label-hint">
Do not include personal or financial information, like your National Insurance number or credit card details.
</div>
</div>
<div class="o-form__input">
<div class="c-input c-input--textarea">
<textarea class="c-input__field" id="f2-thething-textarea" name="f2-thething-textarea" rows="5" aria-describedby="f2-thething-textarea-hint"></textarea>
</div>
</div>
<div class="o-form__alert">
<span class="o-form__alert-content">Please write a brief summary of the issue</span>
</div>
</div>
</div>
</form>