From 4e8318d0ae5859f61fbc05ec0cc007cd00247eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Thu, 3 Jul 2025 08:44:41 +0200 Subject: [PATCH] Improve bookmark form accessibility (#1116) * Bump Django * Render error messages in English * Remove unused USE_L10N option * Associate errors and help texts with form fields * Make checkbox inputs clickable * Change cancel button text * Fix tests --- bookmarks/forms.py | 9 ++- .../frontend/behaviors/tag-autocomplete.js | 1 + .../components/TagAutocomplete.svelte | 2 + bookmarks/settings/base.py | 2 - bookmarks/styles/theme/forms.css | 13 ++-- bookmarks/templates/bookmarks/form.html | 37 +++++------ bookmarks/templates/shared/error_list.html | 6 ++ bookmarks/templatetags/shared.py | 27 ++++++++ bookmarks/tests/test_bookmark_edit_view.py | 33 +++++----- bookmarks/tests/test_bookmark_new_view.py | 61 ++++++++++--------- .../e2e_test_bookmark_details_modal.py | 2 +- requirements.dev.txt | 4 +- requirements.txt | 4 +- 13 files changed, 123 insertions(+), 78 deletions(-) create mode 100644 bookmarks/templates/shared/error_list.html diff --git a/bookmarks/forms.py b/bookmarks/forms.py index bdd15c0..5aa3efc 100644 --- a/bookmarks/forms.py +++ b/bookmarks/forms.py @@ -1,4 +1,5 @@ from django import forms +from django.forms.utils import ErrorList from bookmarks.models import Bookmark, build_tag_string from bookmarks.validators import BookmarkURLValidator @@ -6,6 +7,10 @@ from bookmarks.type_defs import HttpRequest from bookmarks.services.bookmarks import create_bookmark, update_bookmark +class CustomErrorList(ErrorList): + template_name = "shared/error_list.html" + + class BookmarkForm(forms.ModelForm): # Use URLField for URL url = forms.CharField(validators=[BookmarkURLValidator()]) @@ -48,7 +53,9 @@ class BookmarkForm(forms.ModelForm): if instance is not None and request.method == "GET": initial = {"tag_string": build_tag_string(instance.tag_names, " ")} data = request.POST if request.method == "POST" else None - super().__init__(data, instance=instance, initial=initial) + super().__init__( + data, instance=instance, initial=initial, error_class=CustomErrorList + ) @property def is_auto_close(self): diff --git a/bookmarks/frontend/behaviors/tag-autocomplete.js b/bookmarks/frontend/behaviors/tag-autocomplete.js index 7221582..1e0c245 100644 --- a/bookmarks/frontend/behaviors/tag-autocomplete.js +++ b/bookmarks/frontend/behaviors/tag-autocomplete.js @@ -19,6 +19,7 @@ class TagAutocomplete extends Behavior { name: input.name, value: input.value, placeholder: input.getAttribute("placeholder") || "", + ariaDescribedBy: input.getAttribute("aria-describedby") || "", variant: input.getAttribute("variant"), }, }); diff --git a/bookmarks/frontend/components/TagAutocomplete.svelte b/bookmarks/frontend/components/TagAutocomplete.svelte index 8214eca..7a7b95d 100644 --- a/bookmarks/frontend/components/TagAutocomplete.svelte +++ b/bookmarks/frontend/components/TagAutocomplete.svelte @@ -6,6 +6,7 @@ export let name; export let value; export let placeholder; + export let ariaDescribedBy; export let variant = 'default'; let isFocus = false; @@ -110,6 +111,7 @@ diff --git a/bookmarks/settings/base.py b/bookmarks/settings/base.py index 559ef8d..563337d 100644 --- a/bookmarks/settings/base.py +++ b/bookmarks/settings/base.py @@ -116,8 +116,6 @@ TIME_ZONE = os.getenv("TZ", "UTC") USE_I18N = True -USE_L10N = True - USE_TZ = True # Static files (CSS, JavaScript, Images) diff --git a/bookmarks/styles/theme/forms.css b/bookmarks/styles/theme/forms.css index 0a5b6ae..6be8773 100644 --- a/bookmarks/styles/theme/forms.css +++ b/bookmarks/styles/theme/forms.css @@ -224,12 +224,13 @@ textarea.form-input { position: relative; input { - clip: rect(0, 0, 0, 0); - height: 1px; - margin: -1px; - overflow: hidden; + opacity: 0; position: absolute; - width: 1px; + top: calc((var(--control-size-sm) - var(--control-icon-size)) / 2); + left: 0; + height: var(--control-icon-size); + width: var(--control-icon-size); + cursor: pointer; &:focus-visible + .form-icon { outline: var(--focus-outline); @@ -243,9 +244,9 @@ textarea.form-input { } .form-icon { + pointer-events: none; border: var(--border-width) solid var(--checkbox-border-color); box-shadow: var(--input-box-shadow); - cursor: pointer; display: inline-block; position: absolute; transition: diff --git a/bookmarks/templates/bookmarks/form.html b/bookmarks/templates/bookmarks/form.html index 309dfc5..542ea59 100644 --- a/bookmarks/templates/bookmarks/form.html +++ b/bookmarks/templates/bookmarks/form.html @@ -1,5 +1,6 @@ {% load widget_tweaks %} {% load static %} +{% load shared %}
{% csrf_token %} @@ -7,7 +8,7 @@
- {{ form.url|add_class:"form-input"|attr:"autofocus"|attr:"placeholder: " }} + {{ form.url|form_field:"validation"|add_class:"form-input"|attr:"autofocus" }}
{% if form.url.errors %} @@ -22,8 +23,8 @@
- {{ form.tag_string|add_class:"form-input"|attr:"autocomplete:off"|attr:"autocapitalize:off" }} -
+ {{ form.tag_string|form_field:"help"|add_class:"form-input"|attr:"autocomplete:off"|attr:"autocapitalize:off" }} +
Enter any number of tags separated by space and without the hash (#). If a tag does not exist it will be automatically created.
@@ -35,7 +36,8 @@
-
@@ -60,31 +62,31 @@ Notes - {{ form.notes|add_class:"form-input"|attr:"rows:8" }} -
+ {{ form.notes|form_field:"help"|add_class:"form-input"|attr:"rows:8" }} +
Additional notes, supports Markdown.
{{ form.notes.errors }}
-