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

  1. Simple
  2. Input with button
  3. Newsletter
  4. Fieldsets

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.

Optional extra label text

With Error state

Optional extra label text
Please enter your full name

Input with button

Single input with adjacent button

this won’t align with a label above input

Please enter your full name

Aligned input with button

this aligns even with a label above each input, except error message

Please enter your full name

Multiple inputs with adjacent button

Please enter your first name
Please enter your last name
 

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’)

Please enter your surname
Your email address appears to be missing an @ symbol verbose comment
Optional extra label text (date format eg, 27/03/2019)
Please choose a region

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.

Fieldset of radio options

Extra 'label' text (should provide a hint to completing the input)

Fieldset of checkbox options

Extra 'label' text (should provide a hint to completing the input), choose one or more options
Please choose at least one label
Do not include personal or financial information, like your National Insurance number or credit card details.
Please write a brief summary of the issue

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 &amp; Wales</option>
                        <option value="northeast">Yorkshire &amp; 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>

JS - Parameters

References / inspiration