Skip to content

Commit 3e59647

Browse files
Set the help_text id attribute to the field aria-describedby (#716)
Otherwise, the rendered HTML does contains an `aria-describedby` that references a nonexistent element.
1 parent 5b0c637 commit 3e59647

File tree

5 files changed

+21
-3
lines changed

5 files changed

+21
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Switch to just and uv for package management (#734).
66
- Remove `<nav>` from pagination (#686, @xi).
7+
- Add an `id` to the help text of fields for Django 5.0+, to match the `aria-describedby` attribute.
78
- Drop support for Python 3.8 in the test matrix
89

910
## 24.3 (2024-09-17)

src/django_bootstrap5/renderers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,14 @@ def get_help_html(self):
394394
"""Return HTML for help text."""
395395
help_text = self.help_text or ""
396396
if help_text:
397+
widget_attrs = self.field.build_widget_attrs(self.widget.attrs)
398+
aria_describedby = widget_attrs.get("aria-describedby")
397399
return render_template_file(
398400
self.field_help_text_template,
399401
context={
400402
"field": self.field,
401403
"help_text": help_text,
404+
"id_help_text": aria_describedby,
402405
"layout": self.layout,
403406
"show_help": self.show_help,
404407
},
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{% if help_text %}<div class="form-text">{{ help_text|safe }}</div>{% endif %}
1+
{% if help_text %}<div {% if id_help_text %}id="{{ id_help_text }}" {% endif %}class="form-text">{{ help_text|safe }}</div>{% endif %}

tests/test_bootstrap_field.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django import forms
22

3-
from .base import BootstrapTestCase
3+
from .base import DJANGO_VERSION, BootstrapTestCase
44

55

66
class XssTestForm(forms.Form):
@@ -24,10 +24,21 @@ def test_illegal_field(self):
2424
def test_show_help(self):
2525
html = self.render("{% bootstrap_field form.subject %}", {"form": SubjectTestForm()})
2626
self.assertIn("my_help_text", html)
27+
if DJANGO_VERSION >= "5":
28+
self.assertIn('aria-describedby="id_subject_helptext"', html)
29+
self.assertIn('<div id="id_subject_helptext" class="form-text">my_help_text</div>', html)
2730
self.assertNotIn("<i>my_help_text</i>", html)
2831
html = self.render("{% bootstrap_field form.subject show_help=False %}", {"form": SubjectTestForm()})
2932
self.assertNotIn("my_help_text", html)
3033

34+
if DJANGO_VERSION >= "5":
35+
36+
def test_help_text_overridden_aria_describedby(self):
37+
form = SubjectTestForm()
38+
form.fields["subject"].widget.attrs["aria-describedby"] = "my_id"
39+
html = self.render("{% bootstrap_field form.subject %}", {"form": form})
40+
self.assertIn('<div id="my_id" class="form-text">my_help_text</div>', html)
41+
3142
def test_placeholder(self):
3243
html = self.render("{% bootstrap_field form.subject %}", {"form": SubjectTestForm()})
3344
self.assertIn('type="text"', html)

tests/test_bootstrap_form.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,17 @@ def test_exclude(self):
3838
)
3939
if DJANGO_VERSION >= "5":
4040
html = html.replace(' aria-describedby="id_required_text_helptext"', "")
41+
help_text = '<div id="id_required_text_helptext" class="form-text"><i>required_text_help</i>'
42+
else:
43+
help_text = '<div class="form-text"><i>required_text_help</i>'
4144
self.assertHTMLEqual(
4245
html,
4346
(
4447
'<div class="mb-3 django_bootstrap5-req">'
4548
'<label class="form-label" for="id_required_text">Required text</label>'
4649
'<input type="text" name="required_text" class="form-control"'
4750
' placeholder="Required text" required id="id_required_text">'
48-
'<div class="form-text"><i>required_text_help</i>'
51+
f"{help_text}"
4952
"</div>"
5053
),
5154
)

0 commit comments

Comments
 (0)