Opened 42 minutes ago
#37298 new Bug
Admin radio_fields have an invalid aria-describedby attribute.
| Reported by: | David Smith | Owned by: | |
|---|---|---|---|
| Component: | contrib.admin | Version: | 6.1 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
#35892 added support for Widget.use_fieldset in admin forms. Refs 4187da258fe212d494cb578a0bc2b52c4979ab95
An incorrect aria-describedby attribute is generated for radio_fields with help_text and no reference is available for errors.
Given this form:
class Colour(models.Model): name = models.CharField(max_length=100, help_text='Enter your name') COLOUR_CHOICES = [ ('red', 'Red'), ('green', 'Green'), ('blue', 'Blue'),] favourite_colour = models.CharField( max_length=10, choices=COLOUR_CHOICES, help_text='Colour of the favourite colour', )
... and model admin:
class ColourAdmin(admin.ModelAdmin): radio_fields = {"favourite_colour": admin.VERTICAL} model = Colour
Adding a new Colour record in the admin with no inputs gives the following HTML for the favourite_colour field.
Notice how the aria-describedby in the <fieldset> is _helptext. This id does not exist, and also there is no reference to "id_favourite_colour_error" to reference the error list.
<fieldset aria-describedby="_helptext">
<legend class="required">Favourite colour:</legend>
<div class="flex-container errors">
<div class="help">
<div>Colour of the favourite colour</div>
</div>
<ul class="errorlist" id="id_favourite_colour_error">
<li>This field is required.</li>
</ul>
<div id="id_favourite_colour" class="radiolist">
<div>
<label for="id_favourite_colour_0">
<input type="radio" name="favourite_colour" value="red" class="radiolist" required="" aria-invalid="true" id="id_favourite_colour_0" /> Red
</label>
</div>
<div>
<label for="id_favourite_colour_1">
<input type="radio" name="favourite_colour" value="green" class="radiolist" required="" aria-invalid="true" id="id_favourite_colour_1" /> Green
</label>
</div>
<div>
<label for="id_favourite_colour_2">
<input type="radio" name="favourite_colour" value="blue" class="radiolist" required="" aria-invalid="true" id="id_favourite_colour_2" /> Blue
</label>
</div>
</div>
</div>
</fieldset>
Contrast that to the name field where both the help_text and errors have a valid aria-describedby references from the <input>.
Using aria-describedby from the field's boundfield (field.field in this case) is where I'd be looking to fix the issue.
-
django/contrib/admin/templates/admin/includes/fieldset.html
diff --git a/django/contrib/admin/templates/admin/includes/fieldset.html b/django/contrib/admin/templates/admin/includes/fieldset.html index 70c68655c5..4ef3d01589 100644
a b 10 10 {% for line in fieldset %} 11 11 <div class="form-row{% if not line.fields|length == 1 %} flex-container form-multiline{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}"> 12 12 {% for field in line %} 13 {% if field.is_fieldset %}<fieldset{% if field.field. help_text %} aria-describedby="{{ field.field.id_for_label }}_helptext"{% endif %}>{{ field.label_tag }}{% endif %}13 {% if field.is_fieldset %}<fieldset{% if field.field.aria_describedby %} aria-describedby="{{ field.field.aria_describedby }}"{% endif %}>{{ field.label_tag }}{% endif %} 14 14 <div class="flex-container{% if not field.is_readonly and field.errors or line.fields|length == 1 and line.errors %} errors{% endif %}{% if not line.fields|length == 1 %} fieldBox{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if field.field.is_hidden %} hidden{% endif %}{% endif %}{% if field.is_checkbox %} checkbox-row{% endif %}"> 15 15 {% if field.is_checkbox %} 16 16 <div class="checkbox"> … … 21 21 {% if not field.is_fieldset %}{{ field.label_tag }}{% endif %} 22 22 {% endif %} 23 23 {% if field.field.help_text %} 24 <div class="help{% if field.field.is_hidden %} hidden{% endif %}"{% if field.field. id_for_label %} id="{{ field.field.id_for_label}}_helptext"{% endif %}>24 <div class="help{% if field.field.is_hidden %} hidden{% endif %}"{% if field.field.auto_id %} id="{{ field.field.auto_id }}_helptext"{% endif %}> 25 25 <div>{{ field.field.help_text|safe }}</div> 26 26 </div> 27 27 {% endif %}
Then for tests I'd suggest looking at the test that was added for admin fieldsets. Additional tests can be added to assert the correct aria-describedby attribute for both help_text and errors is present.
https://github.com/django/django/blob/0b40210e4808937a7c0922e8b7502bff4752faa3/tests/admin_views/tests.py#L7365