Display the Focus Outline Only for Keyboard Usage with React Hooks

Tags: react, ux, css, a11y
Published: 2020-05-17 19:14:11

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:
```css
*: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](https://media.giphy.com/media/1zSz5MVw4zKg0/giphy.gif)


## 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"](https://media.giphy.com/media/1qhAeOZnZUm8oEauce/giphy.gif)

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](https://dev-to-uploads.s3.amazonaws.com/i/ojag0okik7gb649p51mu.gif)

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:
```javascript
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`:
```javascript
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:
```javascript
<App className={mouseDown ? 'mousedown' : ''}>
```

### Step 4

And the final step is to remove the outline for all elements inside `App` when using a mouse:
```css
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:
{% codepen https://codepen.io/dysanio/pen/QWjZYJW %}

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