Focus hell

Thomas Genissel
Oct 1, 2019 · 6 min read

Design that meets accessibility requirements is a mandatory concern at iAdvize. As we refactor our solution to be WCAG AA compliant, we’ve come across a hot debate: how should we handle the “focus” state in our UI? It sounded like simple enough question at first, yet it has sparked many conversations between designers, developers and product managers alike.

It has helped us grow and we did find a few solutions, but before we discuss those, let’s have a little reminder about WCAG requirements when it comes to keyboard navigation and focus rings.

WCAG Requirement

2.1.1 Keyboard: All functionalities of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user’s movement and not just the endpoints. (Level A)

2.4.7 Focus Visible: Any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible. (Level AA)

All the features in our solution must be operable through a keyboard interface (a “keyboard interface” could also be a head or mouth stick). Fulfilling this first requirement implies displaying a “focus” feedback, without which navigation wouldn’t be visible on screen, thus the second requirement: the focus indicator must be visible. Note that “visible” is relatively subjective. There is no notion of contrast ratio, colors, size, etc in the WCAG spec here. It should just be “visible”…

Designers requirements

Our designers have expressed two requests.

First, their normalized design language for a focused element implies that when there is a focus ring, it must be styled with a box-shadow instead of the native outline. In our solution, most of our outlines were then removed with a nice `outline: none`. Outlinenone.com is here to remind us that when we write `outline: none`, we have to implement an alternative to be WCAG compliant. No outline should not mean no visible focus, and our box-shadows do just that.

Their second request was to hide the focus ring or indicator when the user is using a mouse. The design team doesn’t want to see a focus ring after a click on a button, as it seems redundant. We discovered that if you have a native button without custom CSS style, the button won’t show the focus after it’s clicked. But when you add custom CSS on it, even if that style has nothing to do with its focus, it will now show the native focus outline for the mouse input too 🤷‍♂️.

The first requirement is actually not as easy as it might seem, and the second one is the main purpose of this article.

Solutions

We’ve charted out multiple solutions trying to satisfy both requirements while remaining accessible. Let’s walk through each of them.

1. :focus-visible

It’s currently a W3C proposal for styling keyboard-only focus using CSS.

Until major browsers support it, you can use this robust polyfill. It is nice because it doesn’t require adding extra elements or altering the tabindex.

Image for post
Image for post

However, in some parts of our solution we have drastic constraints about our bundle size, so using a polyfill is not the best solution for us.

2. Event listener

We can use Javascript to detect when users click their mouse or use their keyboard, then toggle a class on the body : <body class=”using-mouse”>

CSS rules can then use that class to show or hide the appropriate focus styling on the relevant elements.

Image for post
Image for post

We have implemented this solution in a large part of our product. It is pretty easy to set-up, but it makes more sense when implemented at t the beginning of a project: the earlier this parent class is taken into account, the easier it is to build your consistent focus styles around it.

If you use only outline styling to implement the focus indicator strategy for your whole codebase, this solution is perfect… but if you use box-shadow or border, it may be more difficult to maintain. For example if you have an element featuring a box-shadow with and without focus, you will be forced to implement specific code for this element. Your focus styling strategy may conflict with your regular styles. It’s the crucial limit of this solution.

3. Button content

We can wrap the content of the original interactive element inside an additional inner element with tabindex=”-1" and remove focus styling for this inner element.

Image for post
Image for post

This solution meets our designers’ second requirement: keyboard users will see a focus outline (native or otherwise) where they should, but mouse users, hitting that inner element, never will.

If you are refactoring component by component, this solution may be useful. We used it to refactor our notifications system. Notifications are displayed in multiple apps and pages. Because our style is scoped to our component, this method ensures it will have the same behavior everywhere it’s called and we don’t need to inject event listeners or impose a parent class anywhere.

4. Blur after click

We can handle each click on a button and force a blur event on that element right after a click. In this example it’s after a form submission:

Image for post
Image for post

We’ve never used this technique. It’s the last resort solution, too ugly to be used by default…but it would certainly remove the focus indicator after an interaction has been performed, still fulfilling that second design requirement.

5. Pragmatic way

Achieving keyboard-only focus styles is surprisingly difficult, and until :focus-visible is universally supported without polyfill, it seems bound to stay difficult, or at least time-consuming.

There’s always the other option: spend no time on it and let the browser do its native job.

In some environments this solution might be good enough. Do not mess with the native outline behaviour with your CSS, do not develop JS-based catches and you’ll meet WCAG criterias. What you won’t meet though is product and design requests. It’s important that the whole team estimates how valuable that compromise is before acting on it.

Conclusion

Our problem is twofold: first we want to be WCAG-compliant with our focus indicators, but we also do not want them to appear outside of WCAG-centric use cases (in this case, keyboard navigation).

The hardest part was to reconcile fairly opposite needs. We needed a quick, fool-proof focus indicator method for accessibility, yet we also wanted a well-designed and thorough solution.

With that in mind, the solutions we’ve explored all feel like we’re making a compromise, because we are! We’ve however found with them a fairly robust toolset with which we can meet the necessary requirements, should they come from WCAG criterias or from our own product design team. Depending on their toll on a feature’s complexity, time management or overall maintainability, we know we can pick one of these tools and achieve our goals.

Sources :

We didn’t change the world of focus management, we just want give a feedback on some techniques we discover and tried. Most of solutions are explained in this topic:

https://stackoverflow.com/questions/31402576/enable-focus-only-on-keyboard-use-or-tab-press

For more details about the WCAG spec:

https://www.w3.org/TR/WCAG21/

iAdvize Engineering

Publications from the iAdvize engineering team :)

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store