fix(a11y): Make recurrence modal fully keyboard-accessible#1533
fix(a11y): Make recurrence modal fully keyboard-accessible#1533
Conversation
a2acead to
d039306
Compare
Make modal focus trap dynamic: re-query visible focusable elements on each Tab press so that AJAX-loaded content (occurrence lists) and dynamically shown/hidden fields are always reachable via keyboard. Ref: plone/Products.CMFPlone#4272
- Change occurrence action links (<a href="#">) to <button> elements for proper semantics and native keyboard support (Enter + Space). - Change display widget "Add"/"Delete" links to <button> elements. - Update all matching JS selectors and CSS rules. - Add focus-visible outline styles for occurrence action buttons. - Add tests verifying button elements are used. Fixes: plone/Products.CMFPlone#4272
d039306 to
d9b3ff3
Compare
thet
left a comment
There was a problem hiding this comment.
LGTM
Especially the button change is great.
The dynamic re-evaluation of tab presses sounds a bit expensive, but might be OK too. I'll paste a conversation with an AI on this issue and got a convincing answer, so this improvement LGTM.
|
Btw. I changed the single commit combining two different changes into two commits, as it is the convention in Mockup and Patternslib. |
thet
@{agent} In the referenced context buffer we have a focusTrapHandler, which is run for each
CodeCompanion (Copilot)Here are answers to your questions based on the provided code:
So, while the handler covers keyboard navigation via
Using a Summary:
If you want stricter focus trapping or to experiment with MutationObserver-based caching, let me know and I can implement an example for you. thet
|
|
OK, the AI is right, it covers only tab-key, but that was the original issue: keyboard accessibility. @thet do you merge or shall I? |
|
Just found out that this breaks one robottest here https://github.com/plone/mockup/actions/runs/22964406148/job/66663816140#step:15:107 ... needs to be fixed here https://github.com/plone/plone.app.event/blob/master/src/plone/app/event/tests/robot/test_event_roundtrip.robot#L83 |
|
The PR changed |
The recurrence widget's 'Add rules' button was changed from <a> to <button> in plone/mockup#1533 for accessibility. Use //*[@name="riedit"] instead of //a[@name="riedit"] so the test works with both old and new mockup versions.
Branch: refs/heads/master Date: 2026-03-11T22:37:12+01:00 Author: Jens W. Klein (jensens) <jk@kleinundpartner.at> Commit: plone/plone.app.event@403d120 fix(robot): Use element-agnostic XPath for riedit selector The recurrence widget's 'Add rules' button was changed from <a> to <button> in plone/mockup#1533 for accessibility. Use //*[@name="riedit"] instead of //a[@name="riedit"] so the test works with both old and new mockup versions. Files changed: M src/plone/app/event/tests/robot/test_event_roundtrip.robot Repository: plone.app.event Branch: refs/heads/master Date: 2026-03-11T22:38:31+01:00 Author: Jens W. Klein (jensens) <jk@kleinundpartner.at> Commit: plone/plone.app.event@3db6648 Add towncrier news entry for #432 Files changed: A news/432.tests Repository: plone.app.event Branch: refs/heads/master Date: 2026-03-11T22:47:37+01:00 Author: Jens W. Klein (jensens) <jk@kleinundpartner.at> Commit: plone/plone.app.event@d60dc96 Update configuration via plone/meta 2.x Adds setuptools<82.0.0 to dependencies tox env to fix ModuleNotFoundError: No module named 'pkg_resources'. Also updates isort, black, pyupgrade targets and setuptools version constraint. Files changed: A news/+meta.internal M .github/workflows/test-matrix.yml M .meta.toml M .pre-commit-config.yaml M pyproject.toml M tox.ini Repository: plone.app.event Branch: refs/heads/master Date: 2026-03-11T22:50:04+01:00 Author: Jens W. Klein (jensens) <jk@kleinundpartner.at> Commit: plone/plone.app.event@17abd26 Apply isort 8 import ordering fixes Files changed: M docs/conf.py M setup.py M src/plone/app/event/__init__.py M src/plone/app/event/base.py M src/plone/app/event/dx/behaviors.py M src/plone/app/event/ical/exporter.py M src/plone/app/event/interfaces.py M src/plone/app/event/portlets/portlet_calendar.py M src/plone/app/event/setuphandlers.py M src/plone/app/event/tests/base_setup.py M src/plone/app/event/tests/robot/variables.py M src/plone/app/event/tests/test_dx_behaviors.py M src/plone/app/event/tests/test_icalendar.py M src/plone/app/event/tests/test_portlet_calendar.py M src/plone/app/event/tests/test_portlet_events.py M src/plone/app/event/tests/test_recurrence.py M src/plone/app/event/upgrades/upgrades.py Repository: plone.app.event Branch: refs/heads/master Date: 2026-03-12T07:19:32+01:00 Author: Peter Mathis (petschki) <petschki@users.noreply.github.com> Commit: plone/plone.app.event@ffc29bb Merge pull request #433 from plone/config-with-default-template-2.5.1 Update configuration via plone/meta 2.x Files changed: A news/+meta.internal A news/432.tests M .github/workflows/test-matrix.yml M .meta.toml M .pre-commit-config.yaml M docs/conf.py M pyproject.toml M setup.py M src/plone/app/event/__init__.py M src/plone/app/event/base.py M src/plone/app/event/dx/behaviors.py M src/plone/app/event/ical/exporter.py M src/plone/app/event/interfaces.py M src/plone/app/event/portlets/portlet_calendar.py M src/plone/app/event/setuphandlers.py M src/plone/app/event/tests/base_setup.py M src/plone/app/event/tests/robot/test_event_roundtrip.robot M src/plone/app/event/tests/robot/variables.py M src/plone/app/event/tests/test_dx_behaviors.py M src/plone/app/event/tests/test_icalendar.py M src/plone/app/event/tests/test_portlet_calendar.py M src/plone/app/event/tests/test_portlet_events.py M src/plone/app/event/tests/test_recurrence.py M src/plone/app/event/upgrades/upgrades.py M tox.ini
Summary
Fixes plone/Products.CMFPlone#4272
The recurrence modal had two keyboard accessibility issues:
<a href="#">instead of proper<button>elementsChanges
pat/modal/modal.js):activateFocusTrap()now re-queries visible focusable elements on each Tab keypress instead of using a static list captured at init. This benefits all modals across Plone, not just recurrence.occurrence.xml,display.xml,recurrence.js): Changed occurrence action links and display widget "Add"/"Delete" links from<a href="#">to<button type="button">for proper semantics and native keyboard support (Enter + Space).recurrence.scss): Updated selector fromdiv.ridisplay .rimain atodiv.ridisplay .rimain button. Added:focus-visibleoutline for occurrence action buttons.recurrence.test.js): Added tests verifying<button>elements are used for display controls and dynamically added date actions.Test plan