loading...
Cover image for Display the Focus Outline Only for Keyboard Usage with React Hooks

Display the Focus Outline Only for Keyboard Usage with React Hooks

dysanio profile image Dan Maniés Updated on ・2 min read

Clickable elements like buttons have an outline by default when targeted by the keyboard or activated by the mouse. Especially the latter behavior is not so popular, because it's ugly. Especially, when a click on a button doesn't load a new page and the outline will remain until you click somewhere else.

A cheap trick to prevent this behavior is following:

*:focus {
  outline: 0;
}

Cool, there's no ugly outline after clicking an element anymore! But wait... There's a huge problem with this approach: you screw keyboard users. This outline is pretty important and common to highlight the current position while navigating with the keyboard. Not everybody uses a mouse and by hiding the outline you exclude those people.

Gif to stop it

A simple solution

I'm building my new website with React right now and I try to take care of accessibility as good as possible. And when I tried to use the keyboard on my website I didn't see my current position. Why? Because I used the cheap trick mentioned above... Then I deleted those few lines and it worked but I was not a fan of the impact on the design.

Gif with the label "This does not look good"

My plan was to show the outlines for keyboard users, but not when using a mouse. In the end, I came up with a simple solution based on react hooks and this is how it looks like:

Demonstration of the solution

Nice, isn't it? Do you want to know how I implemented it? Yes?! Here we go!

Step 1

At first we need a state hook to differ if a mouse was used or not:

const [mouseDown, setMouseDown] = useState(false);

Step 2

Then we need an effect hook to listen to the mousedown and the keydown event to set then the right state of mouseDown:

useEffect(() => {
 document.addEventListener('mousedown', function (event) {
  setMouseDown(true)
 });

 document.addEventListener('keydown', function (event) {
  setMouseDown(false)
 });
}, []);

Step 3

Now we add the class mousedown to the wrapper of your project (here we use App) just when the mouse was clicked:

<App className={mouseDown ? 'mousedown' : ''}>

Step 4

And the final step is to remove the outline for all elements inside App when using a mouse:

App.mousedown *:focus {
 outline: 0;
}

Of course, you can change the color of the outline (like I did for the dark mode) or style that state completely different, but keep in mind to set the targeted element apart from the rest of the elements. My recommendation is to stick close to default behavior.

Example

To demonstrate how it works you can check out this Codepen snippet. Just click inside and navigate with the Tab key and click the buttons. You can toggle between the general behavior and my little fix:

I hope this post was helpful and if you have any questions or feedback just let me know! Thanks for reading :)

Posted on by:

dysanio profile

Dan Maniés

@dysanio

A passionate UX Designer who loves to bring ideas to live with code.

Discussion

markdown guide