Skip to main content
  1. X-GOVUK projects
  2. GOV.UK Form Builder
  3. Error handling

Error handling

When a form is submitted and there is a problem, communicating that problem in a clear and concise manner is imperative. The form builder provides two ways to do this.

Error messages are displayed immediately above the offending field. They should tell the user how to fix the problem.

Additionally a summary of all the problems with the submission should be displayed at the top of the page. Every error in the summary is a hyperlink that when followed focusses on the problematic field.

This behaviour is provided by the form builder without any need for extra configuration.

A form with multiple errors

Input

= f.govuk_error_summary

h2.govuk-heading-l
  | Register your interest in becoming a teacher

= f.govuk_text_field :welcome_pack_reference_number,
  width: 10,
  label: { text: 'What is your reference number?', size: 's' }

= f.govuk_date_field :welcome_pack_received_on,
  legend: { text: 'When did you receive your welcome pack?', size: 's' }

= f.govuk_collection_select :department_id,
  departments,
  :id,
  :name,
  label: { text: 'Which department will you work in?', size: 's' }

= f.govuk_collection_radio_buttons :welcome_lunch_choice,
  lunch_options,
  :id,
  :name,
  :description,
  legend: { text: 'What would you like for lunch on your first day?', size: 's' }
<%= f.govuk_error_summary %>
<h2 class="govuk-heading-l">
  Register your interest in becoming a teacher
</h2>
<%= f.govuk_text_field :welcome_pack_reference_number, width: 10, label: { text: 'What is your reference number?', size: 's' } %>
<%= f.govuk_date_field :welcome_pack_received_on, legend: { text: 'When did you receive your welcome pack?', size: 's' } %>
<%= f.govuk_collection_select :department_id, departments, :id, :name, label: { text: 'Which department will you work in?', size: 's' } %>
<%= f.govuk_collection_radio_buttons :welcome_lunch_choice, lunch_options, :id, :name, :description, legend: { text: 'What would you like for lunch on your first day?', size: 's' } %>

Output

Register your interest in becoming a teacher

Error: Enter the reference number you received in your welcome pack

When did you receive your welcome pack?

Error: Enter the date you received your welcome pack

Error: Select the department to which you’ve been assigned

What would you like for lunch on your first day?

Error: Select a lunch choice for your first day

Lettuce, tomato and cucumber
With cheese and baked beans
<div class="govuk-error-summary" data-module="govuk-error-summary">
  <div role="alert">
    <h2 class="govuk-error-summary__title">
      There is a problem
    </h2>
    <div class="govuk-error-summary__body">
      <ul class="govuk-list govuk-error-summary__list">
        <li>
          <a data-turbo="false" href="#person-welcome-pack-reference-number-field-error">
            Enter the reference number you received in your welcome pack
          </a>
        </li>
        <li>
          <a data-turbo="false" href="#person-welcome-pack-received-on-field-error">
            Enter the date you received your welcome pack
          </a>
        </li>
        <li>
          <a data-turbo="false" href="#person-department-id-field-error">
            Select the department to which you've been assigned
          </a>
        </li>
        <li>
          <a data-turbo="false" href="#person-welcome-lunch-choice-field-error">
            Select a lunch choice for your first day
          </a>
        </li>
      </ul>
    </div>
  </div>
</div>
<h2 class="govuk-heading-l">
  Register your interest in becoming a teacher
</h2>
<div class="govuk-form-group govuk-form-group--error">
  <label for="person-welcome-pack-reference-number-field-error" class="govuk-label govuk-label--s">
    What is your reference number?
  </label>
  <p class="govuk-error-message" id="person-welcome-pack-reference-number-error">
    <span class="govuk-visually-hidden">
      Error: 
    </span>
    Enter the reference number you received in your welcome pack
  </p>
  <input id="person-welcome-pack-reference-number-field-error" class="govuk-input govuk-input--width-10 govuk-input--error" aria-describedby="person-welcome-pack-reference-number-error" type="text" name="person[welcome_pack_reference_number]" />
</div>
<div class="govuk-form-group govuk-form-group--error">
  <fieldset class="govuk-fieldset" aria-describedby="person-welcome-pack-received-on-error">
    <legend class="govuk-fieldset__legend govuk-fieldset__legend--s">
      When did you receive your welcome pack?
    </legend>
    <p class="govuk-error-message" id="person-welcome-pack-received-on-error">
      <span class="govuk-visually-hidden">
        Error: 
      </span>
      Enter the date you received your welcome pack
    </p>
    <div class="govuk-date-input">
      <div class="govuk-date-input__item">
        <div class="govuk-form-group">
          <label class="govuk-label govuk-date-input__label" for="person-welcome-pack-received-on-field-error">
            Day
          </label>
          <input id="person-welcome-pack-received-on-field-error" class="govuk-input govuk-date-input__input govuk-input--width-2 govuk-input--error" name="person[welcome_pack_received_on(3i)]" type="text" inputmode="numeric">
        </div>
      </div>
      <div class="govuk-date-input__item">
        <div class="govuk-form-group">
          <label class="govuk-label govuk-date-input__label" for="person_welcome_pack_received_on_2i">
            Month
          </label>
          <input id="person_welcome_pack_received_on_2i" class="govuk-input govuk-date-input__input govuk-input--width-2 govuk-input--error" name="person[welcome_pack_received_on(2i)]" type="text" inputmode="numeric">
        </div>
      </div>
      <div class="govuk-date-input__item">
        <div class="govuk-form-group">
          <label class="govuk-label govuk-date-input__label" for="person_welcome_pack_received_on_1i">
            Year
          </label>
          <input id="person_welcome_pack_received_on_1i" class="govuk-input govuk-date-input__input govuk-input--width-4 govuk-input--error" name="person[welcome_pack_received_on(1i)]" type="text" inputmode="numeric">
        </div>
      </div>
    </div>
  </fieldset>
</div>
<div class="govuk-form-group govuk-form-group--error">
  <label for="person-department-id-field-error" class="govuk-label govuk-label--s">
    Which department will you work in?
  </label>
  <p class="govuk-error-message" id="person-department-id-error">
    <span class="govuk-visually-hidden">
      Error: 
    </span>
    Select the department to which you've been assigned
  </p>
  <select id="person-department-id-field-error" class="govuk-select govuk-select--error" aria-describedby="person-department-id-error" name="person[department_id]">
    <option value="1">
      Sales
    </option>
    <option value="2">
      Marketing
    </option>
    <option value="3">
      Finance
    </option>
  </select>
</div>
<div class="govuk-form-group govuk-form-group--error">
  <fieldset class="govuk-fieldset" aria-describedby="person-welcome-lunch-choice-error">
    <legend class="govuk-fieldset__legend govuk-fieldset__legend--s">
      What would you like for lunch on your first day?
    </legend>
    <input value="" autocomplete="off" type="hidden" name="person[welcome_lunch_choice]" id="person_welcome_lunch_choice" />
    <p class="govuk-error-message" id="person-welcome-lunch-choice-error">
      <span class="govuk-visually-hidden">
        Error: 
      </span>
      Select a lunch choice for your first day
    </p>
    <div class="govuk-radios" data-module="govuk-radios">
      <div class="govuk-radios__item">
        <input id="person-welcome-lunch-choice-field-error" aria-describedby="person-welcome-lunch-choice-1-hint" class="govuk-radios__input" type="radio" value="1" name="person[welcome_lunch_choice]" />
        <label for="person-welcome-lunch-choice-field-error" class="govuk-label govuk-label--s govuk-radios__label">
          Salad
        </label>
        <div class="govuk-hint govuk-radios__hint" id="person-welcome-lunch-choice-1-hint">
          Lettuce, tomato and cucumber
        </div>
      </div>
      <div class="govuk-radios__item">
        <input id="person-welcome-lunch-choice-2-field" aria-describedby="person-welcome-lunch-choice-2-hint" class="govuk-radios__input" type="radio" value="2" name="person[welcome_lunch_choice]" />
        <label for="person-welcome-lunch-choice-2-field" class="govuk-label govuk-label--s govuk-radios__label">
          Jacket potato
        </label>
        <div class="govuk-hint govuk-radios__hint" id="person-welcome-lunch-choice-2-hint">
          With cheese and baked beans
        </div>
      </div>
    </div>
  </fieldset>
</div>

Linking errors on the base object to specific fields

Some errors don’t apply to a specific field but the object as a whole. The GOV.UK Design System guidelines suggest that in this case, the error summary link should take the user to the first field. As the form builder doesn’t know the order in which fields will be rendered, it must be specified.

Input

= f.govuk_error_summary link_base_errors_to: :email_address

= f.govuk_email_field :email_address, label: { text: "Email address" }
= f.govuk_phone_field :telephone_number, label: { text: "Phone number" }
<%= f.govuk_error_summary link_base_errors_to: :email_address %>
<%= f.govuk_email_field :email_address, label: { text: "Email address" } %>
<%= f.govuk_phone_field :telephone_number, label: { text: "Phone number" } %>

Output

<div class="govuk-error-summary" data-module="govuk-error-summary">
  <div role="alert">
    <h2 class="govuk-error-summary__title">
      There is a problem
    </h2>
    <div class="govuk-error-summary__body">
      <ul class="govuk-list govuk-error-summary__list">
        <li>
          <a data-turbo="false" href="#person-email-address-field">
            Enter a telephone number or email address
          </a>
        </li>
      </ul>
    </div>
  </div>
</div>
<div class="govuk-form-group">
  <label for="person-email-address-field" class="govuk-label">
    Email address
  </label>
  <input id="person-email-address-field" class="govuk-input" type="email" name="person[email_address]" />
</div>
<div class="govuk-form-group">
  <label for="person-telephone-number-field" class="govuk-label">
    Phone number
  </label>
  <input id="person-telephone-number-field" class="govuk-input" type="tel" name="person[telephone_number]" />
</div>

Custom summary error presenter injection

Although the GDS design system recommends that you use the same summary error message as that on the field there may be situations in which the summary level wording can be used to provide more or less context. Forms containing repeatable nested fields, for example, could use the summary message to clearly point to an attribute error instance.

In such cases a custom error presenter that responds to #formatted_error_messages can be supplied. When a presenter object is provided it will be used directly, when a class is provided it will be instantiated with the associated object’s #errors.messages.

Setup

class ErrorSummaryUpperCasePresenter
  def initialize(error_messages)
    @error_messages = error_messages
  end

  def formatted_error_messages
    @error_messages.map { |attribute, messages| [attribute, messages.first.upcase] }
  end
end

custom_error_presenter = ErrorSummaryUpperCasePresenter

Input

= f.govuk_error_summary(presenter: custom_error_presenter)

= f.govuk_text_field :name,
  label: { text: 'Name' },
  hint: { text: 'You can find it on your birth certificate' }

= f.govuk_date_field :date_of_birth,
  date_of_birth: true,
  legend: { text: 'Enter your date of birth' },
  hint: { text: 'For example, 31 3 1980' }
<%= f.govuk_error_summary(presenter: custom_error_presenter) %>
<%= f.govuk_text_field :name, label: { text: 'Name' }, hint: { text: 'You can find it on your birth certificate' } %>
<%= f.govuk_date_field :date_of_birth, date_of_birth: true, legend: { text: 'Enter your date of birth' }, hint: { text: 'For example, 31 3 1980' } %>

Output

You can find it on your birth certificate

Error: Enter a name

Enter your date of birth
For example, 31 3 1980

Error: Enter a valid date of birth

<div class="govuk-error-summary" data-module="govuk-error-summary">
  <div role="alert">
    <h2 class="govuk-error-summary__title">
      There is a problem
    </h2>
    <div class="govuk-error-summary__body">
      <ul class="govuk-list govuk-error-summary__list">
        <li>
          <a data-turbo="false" href="#person-name-field-error">
            ENTER A NAME
          </a>
        </li>
        <li>
          <a data-turbo="false" href="#person-date-of-birth-field-error">
            ENTER A VALID DATE OF BIRTH
          </a>
        </li>
      </ul>
    </div>
  </div>
</div>
<div class="govuk-form-group govuk-form-group--error">
  <label for="person-name-field-error" class="govuk-label">
    Name
  </label>
  <div class="govuk-hint" id="person-name-hint">
    You can find it on your birth certificate
  </div>
  <p class="govuk-error-message" id="person-name-error">
    <span class="govuk-visually-hidden">
      Error: 
    </span>
    Enter a name
  </p>
  <input id="person-name-field-error" class="govuk-input govuk-input--error" aria-describedby="person-name-hint person-name-error" type="text" name="person[name]" />
</div>
<div class="govuk-form-group govuk-form-group--error">
  <fieldset class="govuk-fieldset" aria-describedby="person-date-of-birth-error person-date-of-birth-hint">
    <legend class="govuk-fieldset__legend govuk-fieldset__legend--m">
      Enter your date of birth
    </legend>
    <div class="govuk-hint" id="person-date-of-birth-hint">
      For example, 31 3 1980
    </div>
    <p class="govuk-error-message" id="person-date-of-birth-error">
      <span class="govuk-visually-hidden">
        Error: 
      </span>
      Enter a valid date of birth
    </p>
    <div class="govuk-date-input">
      <div class="govuk-date-input__item">
        <div class="govuk-form-group">
          <label class="govuk-label govuk-date-input__label" for="person-date-of-birth-field-error">
            Day
          </label>
          <input id="person-date-of-birth-field-error" class="govuk-input govuk-date-input__input govuk-input--width-2 govuk-input--error" name="person[date_of_birth(3i)]" type="text" inputmode="numeric" autocomplete="bday-day">
        </div>
      </div>
      <div class="govuk-date-input__item">
        <div class="govuk-form-group">
          <label class="govuk-label govuk-date-input__label" for="person_date_of_birth_2i">
            Month
          </label>
          <input id="person_date_of_birth_2i" class="govuk-input govuk-date-input__input govuk-input--width-2 govuk-input--error" name="person[date_of_birth(2i)]" type="text" inputmode="numeric" autocomplete="bday-month">
        </div>
      </div>
      <div class="govuk-date-input__item">
        <div class="govuk-form-group">
          <label class="govuk-label govuk-date-input__label" for="person_date_of_birth_1i">
            Year
          </label>
          <input id="person_date_of_birth_1i" class="govuk-input govuk-date-input__input govuk-input--width-4 govuk-input--error" name="person[date_of_birth(1i)]" type="text" inputmode="numeric" autocomplete="bday-year">
        </div>
      </div>
    </div>
  </fieldset>
</div>