The newtab customize panel can open without moving focus to its close button
Categories
(Firefox :: New Tab Page, defect)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox158 | --- | fixed |
People
(Reporter: florian, Assigned: florian)
References
(Blocks 1 open bug)
Details
(Keywords: access)
Attachments
(1 external file)
_CustomizeMenu.scss gives .customize-menu visibility: hidden and transitions visibility 250ms along with the slide-in transform, and CustomizeMenu.jsx focuses the close button from onEntered, which react-transition-group calls 250 ms after the panel starts opening.
Because visibility is transitioned, a style resolution taken at the transition's first sample still computes the from-value, hidden. Nothing in a visibility: hidden subtree has a focusable area, so closeButtonRef.current.focus() is a silent no-op and nothing retries: the panel stays open with focus wherever it was. For a keyboard or screen reader user, the customize panel opens and focus never enters it.
Normally a refresh tick lands inside the enter phase and the panel has computed visible long before onEntered. It does not when the content process's refresh driver is starved: react-transition-group forces only one style resolution, before any property has changed, so the transition is created at the next flush -- and if that flush is the one focus() itself forces, the transition is created and sampled at progress 0, hidden.
Reproduced in about:newtab by driving the panel the way the component does, but with no style flush during the enter phase:
dialog.showModal();
dialog.classList.add("customize-animate-enter");
dialog.getBoundingClientRect(); // resolve style once while hidden
dialog.classList.add("customize-animate-enter-done");
closeButton.focus(); // what onEntered does
// getComputedStyle(dialog).visibility === "hidden", document.activeElement.id === ""
It is also how browser_customize_menu_content.js fails with Close button should be focused when menu becomes visible - timed out after 50 tries under test-verify, where the per-test profile shows no focus change was even attempted.
Fix: transition visibility only on the exit classes, the direction that needs it to keep the panel visible while it slides away. The panel then computes visibility: visible at the first style resolution of the enter phase, so the close button is focusable whenever onEntered runs. The animation does not change: the panel was hidden for one frame of the enter phase, during which the transform holds it off screen anyway.
Test dashboard: https://tests.firefox.dev/test.html?test=browser/extensions/newtab/test/browser/browser_customize_menu_content.js
Comment 1•1 month ago
|
||
| frontend-triage | ||
_CustomizeMenu.scss includes visibility in the 250ms transition on the enter classes, so .customize-menu still computes the from-value hidden at the transition's first sample, and the closeButtonRef.current.focus() that CustomizeMenu.jsx runs from onEntered is a silent no-op with nothing retrying it. visibility: visible arrives only from .customize-animate-enter-done/-enter-active at #216-221, which is why no refresh tick inside the enter phase leaves focus outside the panel.
Fix: Split the rule so visibility 250ms applies only to .customize-animate-exit and .customize-animate-exit-done, the direction that needs it to keep the panel on screen while it slides away, and leave the enter classes transitioning transform alone, so the panel computes visible at the first style resolution of the enter phase. Extend browser_customize_menu_content.js with an a11y-reviewed assertion that the close button is focusable as soon as .customize-animate-enter-active is applied, rather than relying on the existing focus poll to catch this.
Suggested severity: S3. A keyboard or screen reader user intermittently gets the customize panel opened with focus left behind on the page, and Tab still reaches the modal dialog's controls.
If you'd like to provide feedback on this comment, please use the 👍 or 👎 reaction.
If you want to categorize your feedback you can add one of the following tags: ai-triage-wrong-file, ai-triage-wrong-cause, ai-triage-hallucination, ai-triage-out-of-scope, ai-triage-wrong-fix, ai-triage-shallow-fix.
Needinfo hackbot@mozilla.tld to have a patch generated for this bug, include any questions or directions as needed in your comment.
| Assignee | ||
Comment 2•1 month ago
|
||
.customize-menu is visibility: hidden and transitions visibility along with its
slide-in transform, so the first style resolution of the enter phase still
computes hidden. Nothing in a hidden subtree is focusable, so the close button
focus the component takes from onEntered silently does nothing and nothing
retries: the panel opens with focus still outside it.
The exit direction is what needs the transition, to keep the panel visible while
it slides away, so declare visibility only there. The animation is unchanged:
the panel was hidden for one frame of the enter phase, with the transform
holding it off screen anyway.
Updated•1 month ago
|
Comment 4•1 month ago
|
||
| bugherder | ||
Updated•1 month ago
|
Description
•