Keyboard and focus problems axe cannot see: lost focus, single-key shortcuts, no focus in high contrast, board menus, headings #227
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
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#227
Loading…
Add table
Add a link
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?
Accessibility debt that the browser suite's axe run cannot catch. Found in the 2026-09-15 code audit.
1. Focus drops to
<body>after sorting, paging or switching theme (WCAG 2.4.3)htmx 2 puts focus back after a swap only for an element with an
id. These triggers have none:partials/table/head.html:119-122);pagination.html:6,17);core/partials/theme_switch.html:14,21).After Enter, the next Tab starts again at the skip link.
Fix: stable ids (
sort-{{ header.key }},page-prev,page-next,theme-switch-button), plus an e2e test that tabs, presses Enter and checks where focus is.2. Single-key shortcuts that cannot be turned off (WCAG 2.1.4, level A)
app.js:394-420bindsd(discard and next) andj(skip), and:443-465binds/page-wide. They fire whenever focus is outside a field, on buttons and links too, and do not checkevent.isComposing.ddiscards straight away (jobs/capture_views.py:340-347).Fix: a Keyboard shortcuts switch under Settings → Appearance (on by default is allowed if it can be turned off), or a modifier key. Ignore keys while an IME is composing.
3. Text fields have no focus indicator in forced-colours mode
field-inputusesfocus:outline-none(assets/css/app.css:249), which compiles tooutline-style: noneand overrides the base:focus-visibleoutline. The remaining cue, a border colour plus a box-shadow ring, is discarded in forced colours, and there is noforced-colorsrule anywhere. This affects every input, select, textarea and table filter.Fix:
focus:outline-hidden(a transparent outline that forced colours make visible), or@media (forced-colors: active) { outline: 2px solid Highlight }. Add an e2e pass with Playwrightforced_colors="active".4. Board status menus
applications/partials/application_card.html:55-56).data-autosubmitsubmits onchange; in Chromium on Windows, arrowing through a closed select fireschangeat each step, writing a status change and a timeline event for every status passed (WCAG 3.2.2).aria-describedby="board-drag-help"sits on a non-focusable<article>.draggable="true"is set in the template, against the rule stated atapp.js:1255.Fix: name each select by its application; submit on Enter or blur, or with a visible Move button; move the
describedbyto the select; setdraggablefrom the script.5. In Settings and Server settings the
h1is the sidebar labelsettings/base.html:11andserver/base.html:9make the small "Settings" label theh1, and each page's title is anh2at the same level as its sections. About 20 pages announce "Settings" when you jump to the heading.Fix: make the sidebar label a
navaria-labelor anh2, and the page title theh1. Add a check for exactly oneh1naming the page.6. Column resizing
say()inserts a<caption role="status">that replaces the table's accessible name.pointercancelis not handled.Fix: the ARIA splitter pattern (
role="separator",aria-valuenow/min/max) with a neutral name, announcements from a region outside the table, and apointercancelhandler.7. Destructive actions are inconsistent
HTTP_REFERER.Fix:
.btn-dangerand.btn-danger-ghostcomponents, one rule (irreversible actions get a confirmation page; reversible ones act at once with an undo), and Cancel URLs passed by the view.