Skip to content

Commit

Permalink
Set the help_text id attribute to the field aria-describedby (#716)
Browse files Browse the repository at this point in the history
Otherwise, the rendered HTML does contains an `aria-describedby` that
references a nonexistent element.
  • Loading branch information
francoisfreitag authored Dec 10, 2024
1 parent 5b0c637 commit 3e59647
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

## 24.3 (2024-09-17)
Expand Down
3 changes: 3 additions & 0 deletions src/django_bootstrap5/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,14 @@ def get_help_html(self):
"""Return HTML for help text."""
help_text = self.help_text or ""
if help_text:
widget_attrs = self.field.build_widget_attrs(self.widget.attrs)
aria_describedby = widget_attrs.get("aria-describedby")
return render_template_file(
self.field_help_text_template,
context={
"field": self.field,
"help_text": help_text,
"id_help_text": aria_describedby,
"layout": self.layout,
"show_help": self.show_help,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{% if help_text %}<div class="form-text">{{ help_text|safe }}</div>{% endif %}
{% if help_text %}<div {% if id_help_text %}id="{{ id_help_text }}" {% endif %}class="form-text">{{ help_text|safe }}</div>{% endif %}
13 changes: 12 additions & 1 deletion tests/test_bootstrap_field.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django import forms

from .base import BootstrapTestCase
from .base import DJANGO_VERSION, BootstrapTestCase


class XssTestForm(forms.Form):
Expand All @@ -24,10 +24,21 @@ def test_illegal_field(self):
def test_show_help(self):
html = self.render("{% bootstrap_field form.subject %}", {"form": SubjectTestForm()})
self.assertIn("my_help_text", html)
if DJANGO_VERSION >= "5":
self.assertIn('aria-describedby="id_subject_helptext"', html)
self.assertIn('<div id="id_subject_helptext" class="form-text">my_help_text</div>', html)
self.assertNotIn("<i>my_help_text</i>", html)
html = self.render("{% bootstrap_field form.subject show_help=False %}", {"form": SubjectTestForm()})
self.assertNotIn("my_help_text", html)

if DJANGO_VERSION >= "5":

def test_help_text_overridden_aria_describedby(self):
form = SubjectTestForm()
form.fields["subject"].widget.attrs["aria-describedby"] = "my_id"
html = self.render("{% bootstrap_field form.subject %}", {"form": form})
self.assertIn('<div id="my_id" class="form-text">my_help_text</div>', html)

def test_placeholder(self):
html = self.render("{% bootstrap_field form.subject %}", {"form": SubjectTestForm()})
self.assertIn('type="text"', html)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_bootstrap_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,17 @@ def test_exclude(self):
)
if DJANGO_VERSION >= "5":
html = html.replace(' aria-describedby="id_required_text_helptext"', "")
help_text = '<div id="id_required_text_helptext" class="form-text"><i>required_text_help</i>'
else:
help_text = '<div class="form-text"><i>required_text_help</i>'
self.assertHTMLEqual(
html,
(
'<div class="mb-3 django_bootstrap5-req">'
'<label class="form-label" for="id_required_text">Required text</label>'
'<input type="text" name="required_text" class="form-control"'
' placeholder="Required text" required id="id_required_text">'
'<div class="form-text"><i>required_text_help</i>'
f"{help_text}"
"</div>"
),
)
Expand Down

0 comments on commit 3e59647

Please sign in to comment.