DIVs with overflow receiving focus, causing issues for accessibility user
Categories
(Core :: DOM: Selection, defect)
Tracking
()
People
(Reporter: kaushik.patel, Unassigned)
References
Details
Attachments
(2 files)
Comment 1•10 years ago
|
||
Comment 2•10 years ago
|
||
Updated•10 years ago
|
Comment 3•10 years ago
|
||
Comment 4•10 years ago
|
||
Comment 5•10 years ago
|
||
Comment 9•10 years ago
|
||
Comment 10•10 years ago
|
||
Comment 11•10 years ago
|
||
Reporter | ||
Comment 12•10 years ago
|
||
Comment 13•10 years ago
|
||
Comment 14•10 years ago
|
||
Comment 15•10 years ago
|
||
Comment 16•9 years ago
|
||
Comment 17•8 years ago
|
||
Comment 18•8 years ago
|
||
Comment 19•8 years ago
|
||
Comment 20•8 years ago
|
||
Updated•8 years ago
|
Comment 21•8 years ago
|
||
Comment 23•4 years ago
|
||
A more accurate title is "DIVs with [scrollable] overflow receiving focus, causing issues for accessibility user".
Here is a minimal reproduction of the behavior https://jsfiddle.net/sjnpd04v/
This behavior may be beneficial, when the scrollable element contains no focusable children. If the scrollable element would not be able to receive focus, then a keyboard-only user would not be able to focus and scroll the element. This is in fact the case in Chrome, where in the test case above you can not focus the .focusable
div.
When the scrollable element does have focusable children, tabbing through the container becomes unnecessary.
As Craig points out, adding tabindex="-1"
makes the element click focusable on both Firefox and Chrome.
The issue is that it is considerably more difficult to stop this behavior than it is to enable it, which can be done with tabindex="0"
on elements you want to receive focus.
I'm not aware of any way to stop this behavior without JavaScript and even then I don't know how it should be done.
Comment 24•4 years ago
|
||
(In reply to M from comment #23)
This behavior may be beneficial, when the scrollable element contains no focusable children. If the scrollable element would not be able to receive focus, then a keyboard-only user would not be able to focus and scroll the element. This is in fact the case in Chrome, where in the test case above you can not focus the
.focusable
div.
Indeed, and that is precisely why this behaviour was implemented (a long time ago).
When the scrollable element does have focusable children, tabbing through the container becomes unnecessary.
That's true, and in principle, I guess it'd be nice if the scrollable area wasn't focusable in the presence of focusable descendants. In practice, while I'm not super familiar with that area of the code, I imagine trying to actually implement this (accounting for dynamic mutations, CSS hiding, etc.) would be fraught with nasty edge cases and a world of pain.
As Craig points out, adding
tabindex="-1"
makes the element click focusable on both Firefox and Chrome.The issue is that it is considerably more difficult to stop this behavior than it is to enable it, which can be done with
tabindex="0"
on elements you want to receive focus.I'm not aware of any way to stop this behavior without JavaScript and even then I don't know how it should be done.
Add a mousedown listener which calls event.preventDefault(). I realise this might not be feasible in some cases due to other side effects (e.g. it will stop drag events from firing), but I thought it worth noting as a potential solution.
Comment 25•4 years ago
|
||
To be clear, I understand the concern for screen reader users here and it obviously isn't ideal. However, it also wouldn't be ideal if a keyboard only (non-screen reader) user couldn't scroll. I'm not sure we can reasonably sacrifice one for the other.
Comment 26•4 years ago
|
||
Hi James, thanks for the comments! That certainly helps clarify things, and I agree that it is useful and Inclusive for a scrollable element with no focusable children to be tabbable in this way.
In my particular use cases (both the one ~4 years ago and the one from yesterday), a role=listbox element is becoming tabbable in a way that a focus trap is created, which is of course its own (arguably worse) a11y issue. But, knowing that the scrollable-tabbable behavior is useful to some folks, we can work around it with the tabindex=-1 approach by adding an onFocus handler that redirects focus to an item in the listbox.
With that option, the most critical issue I'd like if we could improve here: the mysterious and undocumented behavior that results in my coworkers pulling their hair out trying to figure out why an element without a tabindex is suddenly tabbable, and in only one browser! At the very least it would be great if this was documented somewhere on MDN. Scott O'Hara also mentioned in a discussion yesterday that this behavior was intentional, and added that Chrome had actually tried to ship something similar maybe ~1 year ago but ran into some obstacles. So, perhaps this should also be brought up in the context of a W3C discussion to evaluate whether it belongs in a standards proposal.
Another idea I had -- and I don't know how feasible this would be in terms of both the browser engine and the OS native UI primitives -- would be to focus the scrollbar itself, rather than making the scrollable element tabbable. That would allow e.g. a sighted keyboard-only user to scroll the overflowing element in a way that is handled by the engine/OS, rather than handled spookily inside the DOM. I can't say I've ever seen a pattern like this before (maybe in early DOS days?), but an option I wanted to throw out :)
Thanks again for the attention on this.
Comment 27•4 years ago
|
||
Another issue with the status quo (for sighted keyboard users) is that these scrollable elements when focused do not have any default browser focus indicator. This violates WCAG 2.1 2.4.7 Focus Visible.
I'm also curious what exactly the heuristic is that FF uses to determine whether to place a scrollable element in the tab order? If it's documented somewhere (maybe on MDN as Craig mentioned above), then it'd be easier developers to target these elements when writing code (i.e. to do things like override the default browser focus indicator for all scrollable elements that FF has decided to put in the tab order).
Comment 28•4 years ago
|
||
(In reply to zelliottm from comment #27)
Another issue with the status quo (for sighted keyboard users) is that these scrollable elements when focused do not have any default browser focus indicator. This violates WCAG 2.1 2.4.7 Focus Visible.
How not? When I tab the testcase above I do get a focus ring.
I'm also curious what exactly the heuristic is that FF uses to determine whether to place a scrollable element in the tab order? If it's documented somewhere (maybe on MDN as Craig mentioned above), then it'd be easier developers to target these elements when writing code (i.e. to do things like override the default browser focus indicator for all scrollable elements that FF has decided to put in the tab order).
It's not quite an heuristic. The code is here, and it basically ensures that there's some scroll range, and it's an HTML element. So basically all scrollable boxes that you'd find. The other special-cases there are not particularly interesting, but I can explain them if you want.
Comment 29•4 years ago
|
||
How not? When I tab the testcase above I do get a focus ring.
My bad - I didn't notice the dotted, 1px outline. I was looking for the thick, blue focus ring that is rendered on form controls (https://codepen.io/zelliottm/pen/KKabavq) (I'm used to Chrome's keyboard focus indicator). I'm not sure if it meets contrast requirements per https://www.w3.org/WAI/WCAG21/Understanding/focus-visible-enhanced, but it's better than nothing. :)
Thanks for the link to the code. I guess the problem that I'm encountering is that I want to globally apply a stronger focus indicator to these elements, but I'm unable to do so with a CSS selector as I can with other tabbable elements (i.e. form controls, buttons, arbitrary elements with [tabindex], etc).
Comment 30•4 years ago
|
||
They do match the :focus-visible
pseudo-class, is that not enough?
Comment 31•4 years ago
|
||
In my case that overmatches, I'd like to write as specific of a selector as possible. I think my best approach is to try to copy FF's logic with JavaScript to identify these elements.
Updated•2 years ago
|
Comment 32•2 years ago
|
||
I run into a similar issue implementing a table with virtual scroll capabilities.
<html>
<body>
<h1>Focus test</h1>
<div><button id="el1">focusable element 1</button></div>
<!-- virtual scroll viewport (should never receive focus) -->
<div id="viewport" style="padding:1rem;overflow:auto;width: 200px;height:50px;">
<table border=1>
<tr><td id="el2" tabindex="0">focusable element 2</td></tr>
<tr><td>cell</td></tr>
<tr><td>cell</td></tr>
<tr><td>cell</td></tr>
<tr><td>cell</td></tr>
<tr><td>cell</td></tr>
<tr><td>cell</td></tr>
<tr><td>cell</td></tr>
</table>
</div>
<div><button id="el3">focusable element 3</button></div>
</body>
Firefox focuses the viewport, which should not receive the focus at all.
TAB order(firefox): el1, viewport, el2, el3
TAB order(chrome, webkit): el1, el2, el3
The workaround setting tabindex="-1" to the viewport works, but may introduce other problems (make it focusable via mouse).
Comment 33•2 years ago
|
||
(In reply to dietmar from comment #32)
Firefox focuses the viewport, which should not receive the focus at all.
See comment 24 and comment 25 as to why this occurs. My understanding is that Chromium is looking at implementing this as well, as the inability to keyboard scroll a scrollable area is an accessibility problem. This got implemented in https://bugs.chromium.org/p/chromium/issues/detail?id=585413, though it got reverted and is now being discussed in https://bugs.chromium.org/p/chromium/issues/detail?id=907284.
Comment 34•2 years ago
|
||
First, thanks for those links.
For my use case, it would help if there is a way to disable that behavior without setting tabindex to -1.
Note: I am implementing some custom widgets that controls scrolling by themself (table with virtual scroll, ...).
Comment 35•2 years ago
|
||
So... https://searchfox.org/mozilla-central/rev/77a39e7595198fd30b57550749c15761d30314fb/layout/generic/nsIFrame.cpp#10276 is the relevant code. So ways to disable would be making the element not an HTML element or so... Alternatively, is making the element not focusable at all an option?
- Does setting
-moz-user-focus: none;
(setting-moz-user-focus: normal
back on kids) work? If it doesn't, I'd argue it probably should. - Making the scroller
visibility: hidden
and kidsvisibility: visible
would also work, but that might have the unintended effect of showing the kids unconditionally even if the ancestor is visible (plus hiding the scrollbar) which isn't amazing.
Comment 36•2 years ago
|
||
I want to stress that this is a feature of Firefox, not a bug.
Please do not try to override it unless:
- You give another (ancestor or descendant) container
tabindex="0"
; - You also give it an accessible name;
- You give it an appropriate role;
- And you provide some focus styles.
If you create a scrolling area that cannot be scrolled by keyboard alone, then you will have made a WCAG 2.1 SC 2.1.1 Keyboard (A) failure. If you do not assign an accessible name or role then you risk a 4.1.2 Name, Role, Value (A) failure. If you allow Firefox to scroll the content area for you then you are off the hook.
Given WCAG conformance is a requirement in many government and corporate contexts, creating a failure is a bad idea.
If you create your own "custom scrolling", then ensure a keyboard user can use it with only the keyboard. A scrolling table is quite easy to achieve with no script and very little HTML.
References:
- WCAG 2.1 SC 2.1.1 Keyboard (Level A): https://www.w3.org/WAI/WCAG21/quickref/#keyboard
- WCAG 2.1 SC 4.1.2 Name, Role, Value (Level A): https://www.w3.org/WAI/WCAG21/quickref/#name-role-value
- Keyboard-Only Scrolling Areas: https://adrianroselli.com/2022/06/keyboard-only-scrolling-areas.html
- Under-Engineered Responsive Tables: https://adrianroselli.com/2020/11/under-engineered-responsive-tables.html
Comment 37•2 years ago
|
||
(In reply to Emilio Cobos Álvarez (:emilio) from comment #35)
So... https://searchfox.org/mozilla-central/rev/77a39e7595198fd30b57550749c15761d30314fb/layout/generic/nsIFrame.cpp#10276 is the relevant code. So ways to disable would be making the element not an HTML element or so...
Sorry, I don't get that?
Alternatively, is making the element not focusable at all an option?
- Does setting
-moz-user-focus: none;
(setting-moz-user-focus: normal
back on kids) work? If it doesn't, I'd argue it probably should.
I tried that already, but it seems -moz-user-focus does not have any effect.
Comment 38•2 years ago
|
||
(In reply to Adrian Roselli from comment #36)
I want to stress that this is a feature of Firefox, not a bug.
Please do not try to override it unless:
- You give another (ancestor or descendant) container
tabindex="0"
;
Sure, I always make sure there is a focusable element inside...
If you create a scrolling area that cannot be scrolled by keyboard alone
Point is that my component is perfectly accessible without this firefox feature, and the firefox feature make accessibility worse in this case.
It would really help if I can simply set "-moz-user-focus: none;". But this does not have any effect. Is that expected to work?
Comment 39•2 years ago
|
||
This is a problem for multiple components in React Spectrum, Adobe's component library. We had a similar issue with our table component, which we initially solved by adding tabindex="-1"
to the scrollable element. However, now we realized that this has broken the accessibility tree - the role="presentation"
on this element is ignored and the extra accessible element breaks the grid hierarchy. Another similar case where this is broken is in our date picker component. In both cases we already have focusable children within the scrollable area, and allow the user to scroll with the keyboard so adding an additional tab stop is unnecessary. See issue here: https://github.com/adobe/react-spectrum/issues/3633. You can also see the problem in our docs if you make the window narrow so the date picker scrolls: https://react-spectrum.adobe.com/react-spectrum/DateRangePicker.html.
I can also confirm that -moz-user-focus
does not appear to have an effect, but it would be nice if it did. Perhaps the heuristics could also be improved if there is a focusable element within the scrollable region?
Comment 40•1 year ago
|
||
This also causes problems for a use-case we have in our Next.js app. We have this search box that reflects its value to the URL using Next's router.replace
. The problem is that when there's a scroll container, it just steals the focus in the middle of typing in the input, which is just bad.
Here's a CodeSandbox: https://codesandbox.io/p/sandbox/tender-pine-9x9f38?file=/app/page.tsx:34,1
FWIW, this doesn't happen if I use history.replaceState
instead, but I'd prefer to not bypass the framework's router. I'll file an issue with them as well.
Comment 41•1 year ago
|
||
Here's the issue I filed with Next: https://github.com/vercel/next.js/issues/54838
Comment 42•1 year ago
|
||
As far as I know, Firefox only focuses scroll containers if the user or the page explicitly set focus to them. I don't know of any reason that any other API would focus the container. I wonder if Next's router.replace is calling focus on the container for some reason? That wouldn't impact other browsers, since the container isn't focusable there, but regardless, it's not the correct thing to do.
Comment 43•1 year ago
|
||
IIRC last time I interacted with this bug, scrollable containers were automatic tab stops.
Comment 44•1 year ago
|
||
Yes, they are, but that still requires explicit action by the user (tabbing). Comment 40 suggests that this is somehow happening without the user explicitly tabbing, which shouldn't be the case.
Description
•