Skip to content

Commit f6ba49b

Browse files
peteryatespaulrobertlloydfrankieroberto
authored
Add post on improving accessibility of Rails forms (#153)
* Add post on improving accessibilty of Rails forms * Add illustration to post on improving accessibility of Rails forms * Update side-by-side image for post on improving accessibility of Rails forms * Reword sentence on generating markup Co-authored-by: Frankie Roberto <frankie@frankieroberto.com> * Fix typo where extra word 'a' was left in * Reword the prefixing section to use error helper * Capitalise Design System * Add a third section on link_errors * Reword sentence on title with error prefix Co-authored-by: Paul Robert Lloyd <paulrobertlloyd@users.noreply.github.com> * Minor amendments to make what's going on clearer * Fix 'link_errors' typo Co-authored-by: Frankie Roberto <frankie@frankieroberto.com> * Shorten the subheading slightly Co-authored-by: Frankie Roberto <frankie@frankieroberto.com> * Add closing paragraph Co-authored-by: Frankie Roberto <frankie@frankieroberto.com> Co-authored-by: Paul Robert Lloyd <me+git@paulrobertlloyd.com> --------- Co-authored-by: Paul Robert Lloyd <me+git@paulrobertlloyd.com> Co-authored-by: Frankie Roberto <frankie@frankieroberto.com> Co-authored-by: Paul Robert Lloyd <paulrobertlloyd@users.noreply.github.com>
1 parent 20d38f6 commit f6ba49b

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed
Loading
Loading
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
---
2+
title: Finishing touches for forms
3+
date: 2025-01-05
4+
description: Some tips on making sure forms written in Ruby on Rails are accessible
5+
author:
6+
name: Peter Yates
7+
url: https://github.com/peteryates
8+
image:
9+
src: /assets/posts/finishing-touches-for-forms/illustration.png
10+
alt: Illustration of somebody straightening a picture frame on a wall which says ‘form sweet form’.
11+
opengraphImage: true
12+
---
13+
14+
The [GOV.UK formbuilder](https://govuk-form-builder.netlify.app) makes it easy for Ruby on Rails developers to build forms that follow the rules set out in the [GOV.UK Design System](https://design-system.service.gov.uk/).
15+
16+
It generates the correct HTML, provides a nice API for customising the fields to meet the needs of your service and takes care of clearly displaying any error messages.
17+
18+
There are, however, some suggestions in the Design System guidance that go beyond the remit of the form builder.
19+
20+
They are often forgotten, we'll go over some simple ways to solve them here.
21+
22+
## Positioning the error summary at the top of the page
23+
24+
In addition to making it clear that something is wrong, we also need to tell the user exactly what happened and how to fix it.
25+
26+
[The guidance says](https://design-system.service.gov.uk/components/error-summary#where-to-put-the-error-summary):
27+
28+
> Put the error summary at the top of the main container. If your page includes breadcrumbs or a back link, place it below these, but above the `<h1>`.
29+
30+
This is problematic because the form often isn't the first thing on the page but the form builder needs to be responsible for rendering the error summary to ensure the links and targets are consistent.
31+
32+
We could solve the problem by wrapping the whole page in a `<form>` element, which would allow us to place the error summary wherever we like, but it's a hack. It isn't semantically correct and is likely to lead to other problems.
33+
34+
Thankfully, Rails has our backs. We can use [`content_for`](https://guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method) to insert content into a named block in our layout. If we add a named block called `top_of_main` at the top of our `<main>` element, like this:
35+
36+
```html
37+
<div class="govuk-width-container">
38+
<main class="govuk-main-wrapper" id="main-content">
39+
<%= yield :top_of_main %>
40+
<h1 class="govuk-heading-xl">Default page template</h1>
41+
42+
<!-- the rest of our page -->
43+
```
44+
45+
We can send our error summary from the form to it, like this:
46+
47+
```html
48+
<%= form_with(model: @object, url: some_path) do |form| %>
49+
<%= content_for(:top_of_main) { form.govuk_error_summary } %>
50+
51+
<%= form.govuk_text_field(:how_many_juggling_items) %>
52+
<% end %>
53+
```
54+
55+
And now our error summary is in the right spot.
56+
57+
![Two screenshots side by side showing a form with errors. The left one has the error summary after the h1 and the right one has the error summary first](/assets/posts/finishing-touches-for-forms/error-summary-side-by-side.png)
58+
59+
## Prefixing the page title with 'Error:'
60+
61+
When a form submission results in a validation failure we need to make it clear to the user that something is wrong.
62+
63+
[The guidance says](https://design-system.service.gov.uk/patterns/validation/#how-to-tell-the-user-about-validation-errors):
64+
65+
> Add ‘Error: ’ to the beginning of the page `<title>` so screen readers read it out as soon as possible
66+
67+
This is a little tricky because we need some logic that can determine whether there's an error on the page, and we set the `<title>` in the document `<head>` before we've rendered the form in the `<body>`.
68+
69+
We can use `content_for` here too to place the title where we need it.
70+
71+
```html
72+
<head>
73+
<%= tag.title(yield(:page_title)) %>
74+
<!-- other head content -->
75+
</head>
76+
```
77+
78+
We can use the [GOV.UK Components](https://govuk-components.netlify.app/) [title with error prefix helper](https://govuk-components.netlify.app/helpers/title-with-error-prefix/) to add the 'Error:' prefix whenever `@object.errors.any?` is `true`, and pass the resulting string into the `page_title` content:
79+
80+
```ruby
81+
<%
82+
content_for(:page_title) do
83+
title_with_error_prefix(
84+
"How many implements can you juggle with?",
85+
error: @object.errors.any?
86+
)
87+
end
88+
%>
89+
```
90+
91+
## Making sure error links to checkboxes and radios work
92+
93+
The form builder comes with two ways to build lists of check boxes and radio buttons.
94+
95+
The simplest is to use `#govuk_collection_check_boxes` and `#govuk_collection_radio_buttons`, which mimic the behaviour of [their Rails counterparts](https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-collection_checkboxes).
96+
97+
You just pass in the list of options and the form builder will render them. This works for simple lists.
98+
99+
Sometimes, however, the list needs to be customised a little further. For example we might need [a conditionally revealed questions](https://design-system.service.gov.uk/components/checkboxes#conditionally-revealing-a-related-question) or [a divider](https://design-system.service.gov.uk/components/checkboxes/#add-an-option-for-none).
100+
101+
To support this the form builder comes with the more powerful `#govuk_check_boxes_fieldset` and `#govuk_radio_buttons_fieldset` methods which let the developer build the form field by field.
102+
103+
This power comes at a cost. For example you could write something like this. Here the `delete` will only be shown to admins:
104+
105+
```ruby
106+
f.govuk_radio_buttons_fieldset(:close_ticket)) do
107+
108+
if @user.admin?
109+
f.govuk_radio_button(
110+
:close_ticket,
111+
'delete'
112+
)
113+
end
114+
115+
f.govuk_radio_button(
116+
:close_ticket,
117+
'archive'
118+
)
119+
120+
# the rest of the options
121+
end
122+
```
123+
124+
This would make it impossible for the error summary to accurately link to the first check box or radio button without repeating the logic --- an approach that's going to lead to bugs when it's updated in one place but not the other.
125+
126+
Instead, we have to help the error summary by 'marking' the field we want the error summary to link to with `link_errors: true`. This overrides the ID generation so the link in the error summary will match it.
127+
128+
```ruby
129+
f.govuk_radio_buttons_fieldset(:close_ticket)) do
130+
131+
if @user.admin?
132+
f.govuk_radio_button(
133+
:close_ticket,
134+
'delete',
135+
link_errors: true
136+
)
137+
end
138+
139+
f.govuk_radio_button(
140+
:close_ticket,
141+
'archive',
142+
link_errors: @user.regular_user?
143+
)
144+
145+
# the rest of the options
146+
end
147+
```
148+
149+
Now when there's a validation error, regardless of whether the user is an admin or not the error summary will link to the first option. It's a good idea to write some tests to ensure future changes don't affect it.
150+
151+
---
152+
153+
These finishing touches will help make sure your forms are usable and accessible.
154+
155+
If you have any feedback or suggestions of other form features commonly missed, [let us know](https://github.com/x-govuk/govuk-form-builder/issues/new).

0 commit comments

Comments
 (0)