Skip to content

Instantly share code, notes, and snippets.

@robdodson
Last active July 29, 2021 03:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robdodson/fc680a32c0f2b673fe8bbf85d4acea26 to your computer and use it in GitHub Desktop.
Save robdodson/fc680a32c0f2b673fe8bbf85d4acea26 to your computer and use it in GitHub Desktop.
:focus-visible tabindex

One of the intentions of :focus-visible is to not match if someone mouse-clicks on a div (or other generic element) with a tabindex. The reason is because developers often build custom controls using generic elements and when they unexpectedly show a focus ring on mouse click these same developer reach for :focus { outline: none; } which we really want to discourage.

The spec attempts to explain that :focus-visible should not match when you mouse click an element with a tabindex, but does so in a way that maybe isn't explicit enough. Quoting from the spec:

If the element which supports keyboard input (such as an input element, or any other element that would triggers a virtual keyboard to be shown on focus if a physical keyboard were not present), indicate focus.

This attempts to highlight the concept of "supporting keyboard input". Noteably a div with a tabindex would not meet this criteria.

If the user interacts with the page via a pointing device (mouse, touchscreen, etc.) and the focused element does not support keyboard input, don’t indicate focus.

The key phrasing here is "and the focused element does not support keyboard input". Here we'd argue that since a div with a tabindex does not support keyboard input then it should not match :focus-visible when mouse-clicked. If, however, someone were to add contenteditable to the div, then it would meet the criteria and :focus-visible would match.

I think where this gets a bit confusing is in how the different browsers handle focus. For example, if you mouse click a <button> Chrome and Firefox will focus the button, but do not draw a focus ring because the button does not receive keyboard input. Safari does not focus the button, so it also doesn't draw a focus ring but for different reasons.

Similarly, when you mouse click a div with a tabindex, Chrome and Firefox focus the div but do not draw a focus ring (again, because the div does not receive keyboard input). Safari does draw a ring because it focuses the div and will draw a ring on anything with focus (please correct me if I'm wrong). So all of the browsers agree that the div should have focus, they just disagree around whether it should have a ring or not. I think the spec tries to account for that with this final note:

User agents should also use :focus-visible to specify the default focus style, so that authors using :focus-visible will not also need to disable the default :focus style.

So if the UA stylesheet were to be updated in Safari to use :focus-visible then the div would still have focus, it just wouldn't draw a ring anymore.

@clintfisher
Copy link

clintfisher commented Jul 15, 2021

Oddly enough, I'm finding that both FF and Chrome do show the :focus-visible styles on non-native-focusable elements (div, header, section etc) when using tabindex="-1". I wasn't expecting that. (actually this only happens for me on initial page load, navigating from page to page after that, it does not show the focus outline as expected, this is in a react app).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment