Opened 3 years ago

Last modified 4 months ago

#32819 assigned Bug

Fields’ help text and errors should be associated with input

Reported by: Thibaud Colas Owned by: David Smith
Component: Forms Version: dev
Severity: Normal Keywords: accessibility, ui, forms
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: yes

Description (last modified by Thibaud Colas)

With Django’s default field rendering, all field errors are rendered as a list above the field’s label, and help text is rendered after the field’s form element. Example with as_p:

<ul class="errorlist">
  <li>This field is required.</li>
</ul>
<p>
  <label for="id_duration_required">Duration required:</label>
  <input type="text" name="duration_required" required="" id="id_duration_required">
  <span class="helptext">Help</span>
</p>

One problem for screen reader users is that the association between the errors and the field, and between the help text and the field, is only communicated visually. This is a failure of either WCAG 2.1 level A SC 1.3.1: Info and Relationships, or SC 3.3.2: Labels or Instructions. More importantly, it just makes it harder than necessary for screen reader users to make use of help text, and to identify error messages.

The fix is relatively straightforward – using aria-describedby, as documented in the (non-normative) ARIA1 Using the aria-describedby property to provide a descriptive label for user interface controls technique. Here is another well-known accessibility-oriented UI library that implements this technique: GOV.UK design system – text input with error message.

Here is what implementing aria-describedby would look like in the same example as above:

<div class="errorlist" id="id_duration_required_errorlist">
  <p>This field is required.</p>
</div>
<p>
  <label for="id_duration_required">Duration required:</label>
  <input type="text" name="duration_required" required="" id="id_duration_required" aria-describedby="id_duration_required_errorlist id_duration_required_helptext">
  <span class="helptext" id="id_duration_required_helptext">Help</span>
</p>

We have additional id attributes, aria-describedby, and errorlist is no longer a <ul>. Result in VoiceOver:

https://code.djangoproject.com/raw-attachment/ticket/32819/email-required-ariadescribedby.gif

Unfortunately I tried to have this with the errorlist kept as a ul, but it wasn’t announced by VoiceOver. I haven’t heard of this limitation before so am not sure why that might be the case – I’d appreciate others taking a look if possible.

Attachments (1)

email-required-ariadescribedby.gif (56.5 KB ) - added by Thibaud Colas 3 years ago.
Screen recording of the VoiceOver text-to-speech output, announcing the field label, then error message, then help text.

Download all attachments as: .zip

Change History (27)

by Thibaud Colas, 3 years ago

Screen recording of the VoiceOver text-to-speech output, announcing the field label, then error message, then help text.

comment:1 by Thibaud Colas, 3 years ago

Description: modified (diff)

comment:2 by Thibaud Colas, 3 years ago

Component: contrib.adminForms

comment:3 by Mariusz Felisiak, 3 years ago

Summary: Django forms - fields’ help text and errors should be associated with inputFields’ help text and errors should be associated with input
Triage Stage: UnreviewedAccepted

Thanks. Ideally, we should avoid changing <ul> to <div>. Maybe <ul> could be wrapped by <div>.

comment:4 by Hasan Ramezani, 3 years ago

Owner: changed from nobody to Hasan Ramezani
Status: newassigned

I created a draft PR.

@Mariusz, Could you please check it and let me know if I choose the right direction to fix the problem? If so, I can continue with test adjustment.
@Thibaud, It would be great if you can if it will produce your desired output.

comment:5 by Hasan Ramezani, 3 years ago

Owner: Hasan Ramezani removed
Status: assignednew

comment:6 by PriyanshuGarg26, 2 years ago

Owner: set to PriyanshuGarg26
Status: newassigned

comment:7 by Nimra, 19 months ago

Owner: changed from PriyanshuGarg26 to Nimra

comment:8 by Jacob Walls, 16 months ago

Has patch: set
Patch needs improvement: set

comment:9 by Gregor Jerše, 11 months ago

Owner: changed from Nimra to Gregor Jerše

comment:10 by Gregor Jerše, 11 months ago

Patch needs improvement: unset

comment:11 by Mariusz Felisiak, 11 months ago

comment:12 by Gregor Jerše, 11 months ago

Version: 3.2dev

comment:13 by Natalia Bidart, 11 months ago

Patch needs improvement: set

Note that the PR focuses on solving this issue for help_text.

comment:14 by Mariusz Felisiak, 10 months ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:15 by Mariusz Felisiak <felisiak.mariusz@…>, 10 months ago

Resolution: fixed
Status: assignedclosed

In 966ecdd4:

Fixed #32819 -- Established relationship between form fields and their help text.

Thanks Nimra for the initial patch.

Thanks Natalia Bidart, Thibaud Colas, David Smith, and Mariusz Felisiak
for reviews.

comment:16 by David Smith, 9 months ago

Resolution: fixed
Status: closednew

Reopening as the errors case still requires fixing.

comment:17 by Mariusz Felisiak, 9 months ago

Has patch: unset
Triage Stage: Ready for checkinAccepted

comment:18 by David Smith, 5 months ago

Has patch: set
Owner: changed from Gregor Jerše to David Smith
Status: newassigned

comment:19 by Mariusz Felisiak <felisiak.mariusz@…>, 5 months ago

In 292f1ea9:

Refs #32819 -- Used auto_id instead of id_for_label as unique identifier for the field.

id_for_label is blank for widgets with multiple inputs such as radios
and multiple checkboxes. Therefore , help_text for fields using these
widgets cannot currently be associated using aria-describedby.
id_for_label is being used as a guard to avoid incorrectly adding
aria-describedby to those widgets.

This change uses auto_id as the unique identified for the fields
help_text. A guard is added to avoid incorrectly adding
aria-describedby to inputs by checking the widget's use_fieldset
attribute. Fields rendered in a <fieldset> should have
aria-describedby added to the <fieldset> and not every <input>.

comment:20 by Mariusz Felisiak <felisiak.mariusz@…>, 5 months ago

In 7f0275d8:

[5.0.x] Refs #32819 -- Used auto_id instead of id_for_label as unique identifier for the field.

id_for_label is blank for widgets with multiple inputs such as radios
and multiple checkboxes. Therefore , help_text for fields using these
widgets cannot currently be associated using aria-describedby.
id_for_label is being used as a guard to avoid incorrectly adding
aria-describedby to those widgets.

This change uses auto_id as the unique identified for the fields
help_text. A guard is added to avoid incorrectly adding
aria-describedby to inputs by checking the widget's use_fieldset
attribute. Fields rendered in a <fieldset> should have
aria-describedby added to the <fieldset> and not every <input>.

Backport of 292f1ea90f90ff140617299a25884c8fda24aa64 from main

comment:21 by Mariusz Felisiak, 5 months ago

Triage Stage: AcceptedReady for checkin

comment:22 by Mariusz Felisiak <felisiak.mariusz@…>, 5 months ago

In 557fa51:

Refs #32819 -- Added aria-describedby test for widgets with custom id.

comment:23 by Mariusz Felisiak <felisiak.mariusz@…>, 5 months ago

In eec7e9ba:

Refs #32819 -- Established relationship between form fieldsets and their help text.

This adds aria-describedby for widgets rendered in a fieldset such as
radios. aria-describedby for these widgets is added to the <fieldset>
element rather than each <input>.

comment:24 by Mariusz Felisiak, 5 months ago

Has patch: unset
Triage Stage: Ready for checkinAccepted

comment:25 by David Smith, 4 months ago

Has patch: set

comment:26 by Natalia Bidart, 4 months ago

Patch needs improvement: set

Setting as patch needs improvement because the docs for when a custom aria-describedby is given definitely needs more details/clarification about what the user should do to properly customize the attribute for help text and errors.

Note: See TracTickets for help on using tickets.
Back to Top