Form usage

Title

if the form container has a title, the correct level of heading should be added to the form using the {‘title.heading_level’: ‘CORRECT_HEADING_LEVEL’} property, else this will default to a h2, which may not be correct in all scenarios

Lead text

If the requires leading text, the {‘form.lead’: ‘STRING_OF_LEAD_TEXT’} should contain the lead of text

Additional content

If the form requires text elements, lists, links or additional content to be placed before or after the form, the {‘form.additional_info_before’: ‘STRING_OF_RICH_TEXT_HTML’} or {‘form.additional_info_after’: ‘STRING_OF_RICH_TEXT_HTML’}, should be used. If the information is important, such as instructions, links to help pages or contacts etc, use the {‘form.additional_info_before’: ‘STRING_OF_RICH_TEXT_HTML’} value, as this will be discoverable for all users, if the content is inserted after, it appears after the submit button and some screen reader users may not be aware it is there. Only add the {‘form.additional_info_after’: ‘STRING_OF_RICH_TEXT_HTML’}, for search forms or forms with 1 or 2 inputs and if the content is not important.

Button position

If the form design has a button that is displayed adjacent to an input, the {‘form.button_inline’: true} would need to be set. This should only be used for single input forms, such as search forms

Form error

A form error is presented at the top of a form. It should be used in scenarios where a user’s input data passes validation constraints, but the data does not match records on the system. As an example, if a user attempts login and the credentials do not match, it may be helpful to direct them to some help pages or give them an email to contact the correct department e.g:

 'form': {
    'form_error': 'Your login credentails do not match, please email <a href="mailto:somebody@leeds.ac.uk">Somebody at Leeds</a>',
    'form_error_id': 'formErrorId',
    ...
 }

It is necessary to provide the {‘form_error_id’: ‘UNIQUE_ID_ON_THE_PAGE’} and when the page is sent back, the ID of the form error should be appended to the URL and the attribute tabindex=”-1” should be set to tabindex=”0”. this ensures that the message receives focus and can be consumed by the widest range of devices and assistive technologies.

Centering a form

Where a form needs centering within its container {‘form_centered’: true} should be set

Page title

When a form has errors, it is also best practice to prepend the page title with helpful error text, as an example

<title>Contact us | University of Leeds</title>
...

Would be more helpful to users if it were dynamically changed to

<title>3 errors on form submission - Contact us | University of Leeds</title>

This particularly benefits screen reader users, as the page title is the first thing read out on page load, it also benefits users that may become distracted, especially if they have multiple tabs open.

{% if form %}
  <div class="uol-form__container {{ 'uol-form-container--centered' if form.form_centered }} {{ 'uol-form__container--with-image' if form.img.src }}">

    <div class="uol-form__inner-wrapper">
      {% if form.title %}
        <{{ form.heading_level if form.heading_level else 'h2' }} class="uol-form__title">{{ form.title }}</{{ form.heading_level if form.heading_level else 'h2' }}>
      {% endif %}

      {% if form.lead %}
        <div class="uol-form__lead"><p>{{ form.lead | safe }}</p></div>
      {% endif %}

      {% if form.additional_info_before %}
        <div class="uol-rich-text">
          <div class="uol-form__additional-content uol-form__additional-content--before">
            {{ form.additional_info_before  | safe }}
          </div>
        </div>
      {% endif %}

      {% if form.form_error %}
          {% render '@uol-form-error-msg', { form_error: form.form_error, form_error_id: form.form_error_id } %}
      {% endif %}

      <form class="uol-form {{ 'uol-form--button-inline' if form.button_inline else 'uol-form--button-block' }}" action="{{ form.action }}"
        {% for field in form.fields %}
          {{ 'role=search' if field.type == 'search' }}
        {% endfor %}>

        <div class="uol-form__inputs-wrapper">

          {% block formContent %}
            {% for field in form.fields %}
              {% render '@uol-form-input', field %}
            {% endfor %}
          {% endblock %}

        </div>

        {% if form.additional_info_before_submit_button %}
          <div class="uol-rich-text">
            <div class="uol-form__additional-content">
              {{ form.additional_info_before_submit_button | safe }}
            </div>
          </div>
        {% endif %}

        {% if form.button %}
          <div class="uol-form__button-wrapper">
            {% render '@uol-button', form.button %}
          </div>
        {% endif %}

      </form>

      {% if form.additional_info_after  %}
        <div class="uol-rich-text">
          <div class="uol-form__additional-content uol-form__additional-content--after">
            {{ form.additional_info_after | safe }}
          </div>
        </div>
      {% endif %}
    </div>

    {% if form.img.src %}
      <figure class="uol-form__img-wrapper">
        <img class="uol-form__img" src="{{ form.img.src }}" alt="{{ form.img.alt if form.img.alt else null }}">
      </figure>
    {% endif %}

  </div>
{% endif %}
<div class="uol-form__container  ">

    <div class="uol-form__inner-wrapper">

        <h2 class="uol-form__title">Form with additional content before</h2>

        <div class="uol-rich-text">
            <div class="uol-form__additional-content uol-form__additional-content--before">
                <p>Lead links <a href="/">may be used to offer a user alternative pages</a></p>
                <p>Lead links <a href="/">may be used to offer a user alternative options</a></p>
                <ul>
                    <li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
                    <li>Aliquam tincidunt mauris eu risus.</li>
                    <li>Vestibulum auctor dapibus neque.</li>
                </ul>
            </div>
        </div>

        <form class="uol-form uol-form--button-block" action="/example-form-action">

            <div class="uol-form__inputs-wrapper">

            </div>

        </form>

    </div>

</div>
  • Content:
    .uol-form-container--centered {
      @extend .uol-col;
      @extend .uol-col-m-10;
      @extend .uol-col-xl-8;
    
      margin: 0 auto;
    }
    
    .uol-form__container {
      border: 1px solid $color-border--light;
      border-radius: 6px;
      overflow: hidden;
      margin-bottom: $spacing-6;
    
      &.uol-form-container--centered {
        padding: 0;
      }
    
      .uol-side-nav-container--populated + .uol-homepage-content & {
    
        .uol-form__inner-wrapper {
    
          @include media(">=uol-media-l") {
            flex-basis: 100%;
          }
    
          @include media(">=uol-media-xl") {
            flex-basis: 55.555%;
          }
        }
    
          .uol-form {
    
            @include media(">=uol-media-xl") {
              margin-right: $spacing-6;
            }
          }
    
        .uol-form__img-wrapper {
          display: none;
    
          @include media(">=uol-media-xl") {
            display: inline-flex;
            flex-basis: 44.444%;
          }
        }
      }
    }
    
    .uol-form__inner-wrapper {
      padding: $spacing-5 $spacing-4 $spacing-6;
      background-color: $color-grey--light;
    
      @include media(">=uol-media-l") {
        flex-basis: 58.333%;
        padding: $spacing-5 $spacing-5 2.5rem;
      }
    
      @include media(">=uol-media-xl") {
        flex-basis: 50%;
        padding: 2.5rem $spacing-6;
      }
    
      .uol-form__input-wrapper {
        &::before {
          @include media("<uol-media-m") {
            bottom: 1rem;
          }
        }
      }
    }
    
      .uol-form__title {
        color: $color-font;
        font-size: 2rem;
        line-height: 1.25;
        font-family: $font-family-serif;
        margin: 0;
        padding-bottom: $spacing-2;
    
        + .uol-form {
          padding-top: $spacing-2;
        }
    
        @include media(">=uol-media-m") {
          font-size: 2.25rem;
          line-height: 1.333;
        }
    
        @include media(">=uol-media-l") {
          font-size: 2.625rem;
          line-height: 1.238;
        }
      }
    
      .uol-form__lead {
        display: block;
        color: $color-font;
        font-size: 1.125rem;
        line-height: 1.556;
        font-family: $font-family-sans-serif;
        margin: 0 0 $spacing-6;
        font-weight: normal;
    
        // @include media(">=uol-media-s") {
        //   max-width: 31.5rem;
        // }
    
        @include media(">=uol-media-m") {
          max-width: 32rem;
        }
    
        @include media(">=uol-media-l") {
          font-size: 1.25rem;
          max-width: 41rem;
        }
      }
    
    .uol-form {
      flex-direction: row;
    
      &.uol-form--button-inline {
        @include media(">=uol-media-m") {
          display: flex;
        }
      }
    }
    
    .uol-form__container--with-image {
    
      @include media(">=uol-media-l") {
        display: flex;
      }
    }
    
      .uol-form__img-wrapper {
        background-color: $color-grey--light;
        position: relative;
        display: none;
        z-index: -2;
    
        @include media(">=uol-media-l") {
          display: inline-flex;
          flex-basis: 41.666%;
        }
    
        @include media(">=uol-media-xl") {
          flex-basis: 50%;
        }
      }
    
        .uol-form__img {
          position: absolute;
          min-width: 100%;
          min-height: 100%;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          z-index: -1;
        }
    
        .uol-form--button-inline {
          .uol-form__inputs-wrapper {
            flex: 1;
          }
    
          .uol-form__input-container {
            margin-bottom: 0;
          }
    
          .uol-form__button-wrapper {
            align-self: flex-end;
    
            .uol-button {
              @include button_focus(-6px);
            }
    
            @include media(">=uol-media-m") {
              padding-left: $spacing-4;
            }
    
            @include media(">=uol-media-l") {
              padding-left: $spacing-5;
            }
    
            @include media(">=uol-media-xl") {
              padding-left: $spacing-6;
            }
    
            [class^="uol-button"] {
              width: 100%;
              height: 3.125rem;
              line-height: 0.75;
            }
          }
        }
    
        .uol-form__button-wrapper {
          .uol-form--button-block & {
    
          @include media(">=uol-media-s") {
            display: inline-block;
            width: initial;
          }
    
            .uol-button {
              width: 100%;
            }
          }
        }
    
    .uol-form__additional-content {
      padding: 0;
      margin: 0;
    
      a {
        @include link_focus();
      }
    }
    
    .uol-form__additional-content--before {
      .uol-rich-text & {
        margin: $spacing-4 0;
    
        > * {
          margin-bottom: $spacing-4;
        }
    
        > *:last-child {
          margin-bottom: $spacing-6;
        }
      }
    }
    
    .uol-form__additional-content--after {
      .uol-rich-text & {
        margin: $spacing-6 0 0;
    
        > * {
          margin-bottom: $spacing-4;
        }
    
        > *:last-child {
          margin-bottom: 0;
        }
      }
    }
    
  • URL: /components/raw/uol-form/_form.scss
  • Filesystem Path: src/library/02-components/form/_form.scss
  • Size: 4.4 KB
  • Content:
    export const createAriaLiveRegion = () => {
      if (document.querySelector('.uol-form__container')) {
        const formContainer = document.querySelector('.uol-form__container');
    
        if (!formContainer.querySelector('.uol-form__announcement')) {
          const formAnnouncement = document.createElement('div');
    
          formAnnouncement.setAttribute('aria-live', 'polite')
          formAnnouncement.classList.add('uol-form__announcement')
          formAnnouncement.classList.add('hide-accessible')
          formContainer.appendChild(formAnnouncement);
        }
      }
    }
    
    export const preValidationChecks = () => {
      const submitBtn = document.querySelector('[type="submit"]');
      const passwordFields = document.querySelectorAll('.uol-form__input--password');
      const toggleBtn = document.querySelector('.uol-form__input--password-toggle');
      const checkboxGroups = document.querySelectorAll('[role="group"]');
      
      if (submitBtn) {
        submitBtn.addEventListener('click', () => {
    
          if (passwordFields && submitBtn) {
            passwordFields.forEach( (input) => {
              if (input.getAttribute('type') == 'text') {
                input.setAttribute('type', 'password');
                toggleBtn.setAttribute('data-password-visible', false)
              }
            })
          }
    
          if (checkboxGroups) {
            checkboxGroups.forEach( (group) => {
              if (group.hasAttribute('data-checkboxes-required')) {
                const numRequired = group.getAttribute('data-checkboxes-required');
                const totalChecked = group.querySelectorAll("input:checked").length;
            
                if (totalChecked >= numRequired) {
                  group.setAttribute('data-checkbox-group-invalid', false)
                } else {
                  group.setAttribute('data-checkbox-group-invalid', true)
                }
              }
            })
          }
        })
      }
    }
  • URL: /components/raw/uol-form/form.module.js
  • Filesystem Path: src/library/02-components/form/form.module.js
  • Size: 1.8 KB
{
  "form": {
    "action": "/example-form-action",
    "title": "Form with additional content before",
    "heading_level": "h2",
    "additional_info_before": "<p>Lead links <a href=\"/\">may be used to offer a user alternative pages</a></p><p>Lead links <a href=\"/\">may be used to offer a user alternative options</a></p><ul><li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li><li>Aliquam tincidunt mauris eu risus.</li><li>Vestibulum auctor dapibus neque.</li></ul>"
  }
}