Telephone field: the number box drops aria-describedby and aria-invalid, so its help and errors reach no screen reader #416
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#416
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, by rendering a boundPhoneFieldbeside a plainCharFieldand comparing the markup.Checked again on 2026-10-01 against
mainat0a5cad587: still present.Since #114, Postulo relies on Django writing
aria-describedby="<id>_helptext <id>_error"andaria-invalid="true"on each widget.<c-field-feedback>draws the help and error blocks with those ids. The telephone widget's template writes its own<select>and<input>with only a name and an id. Every other attribute Django computed for the field, including the ARIA pair, is thrown away.templates/partials/phone_widget.html:26-39(the hand-written<select name=… id=…>and<input type="text" name=… id=… value=… class=… inputmode="tel" autocomplete="tel">, which never readwidget.attrs);core/phone_field.py:20-50(PhoneWidget);templates/cotton/field_feedback.html:28-35(the_helptextand_errorblocks the box should point at). The template is used by the single box on Your details and the contact form (<c-field :field="form.phone" />), and by every row ofpartials/phone_numbers.html:34-35, whose feedback is drawn at:88.<input type="text" name="phone_1" id="id_phone_1" value="" class="min-w-0 flex-1" inputmode="tel" autocomplete="tel">, with noaria-describedbyand noaria-invalid. A plainCharFieldin the same form renderedaria-invalid="true" aria-describedby="id_other_helptext id_other_error". A screen-reader user whose number is refused (for example "That number is already recorded on this instance…") lands on a box that announces neither that it is invalid nor why. It is also not described by its help text ("Kept in the international form…").{% include "django/forms/widgets/attrs.html" %}inside each tag, or by rendering each subwidget through itstemplate_name. The number box should then carry the field-levelaria-describedbyandaria-invalidthat Django put inwidget.attrs. Keep the select's ownaria-label.Related to #114 (closed), which fixed the dangling references for fields drawn through
<c-field>but not for this widget. Related to #304, which rebuilds this control as one input group and should carry the fix and its test.Done when
tests/test_assistive_names.pyrenders a boundPhoneFieldwith help text and an error. It asserts that the number box hasaria-invalid="true"and anaria-describedbynaming the_helptextand_errorids that<c-field-feedback>draws, and that both ids exist in the page.