useTabOutline: a React hook for better UX and a11y

I wrote this hook to work around the problem of leaving the outline CSS style enabled, where a toggle button’s outline will “stick” on click— e.g. a hamburger menu button.

Eek! The outline stays after I toggle the menu. But if I disable the outline, the button is much less universally accessible for people who rely on the keyboard to navigate. What to do?

Many posts have been written explaining that the most accessibility (“a11y”) friendly solution to this is to disable outlines when the mouse is being used, and enable them when the tab key is used for navigation.

The problem I set out to solve on a code level for our team was how to do this non-invasively — without making global style changes to body styles — since outlines don’t really show in most link and menu cases, they really are only a problem when they stick. Applying styles is also done in a number of ways, using className, style, or css-in-js solutions like Styled Components, so I wanted to provide our dev team a tool that could be applied easily in any context without making any assumptions about how to do that.

My solution? Why, a React hook of course! 🎉 Instead of manipulating styles directly, it simply provides a hideOutline state for JSX to use however it wants:

Of course, in other cases it’s a lot more convenient to use css-in-js to apply styles, so the hook also provides a hideOutlineStyle state:

From a UX standpoint it feels terrific! Even when doing heavy a11y testing, the transition back and forth between tabbing with full outline support and mouse-based navigation with 100% clean visuals is seamless.

Here’s the hook — enjoy! And come see us at Y’all sometime, y’hear?

Yes, that’s a lot of duplicated add/remove calls but the mixed cases make it hard to condense further. Besides, that’s why you use a hook like this, to avoid having to do it manually! 😎

Just another software engineering dad in Portland, Oregon