Focus management in react
Tags: webdev, beginners, react, tutorial
Published: 2023-01-30 18:43:32

The design and creation of websites should be such that it can be used by everyone. It should also increase usability and reduce confusion for both keyboard-only and screen reader users.

when website are created using react, the content of website are updated very frequently which can lead to issues such as that the focus element is no longer in the dom. And keyboard focus is lost or set to an unexpected element. This means the keyboard-only user has to navigate through the entire page again to get back to where they were. To solve such issues we need to programmatically nudge the keyboard focus in the right direction. Doing this will ensure that the web application can be fully operated with the keyboard only.

### WCAG

Web accessibility (also referred to as a11y) requires that we create website by following WCAG ( Web Content Accessibility Guidelines ). The WCAG checklists includes lot of things such as

- Every HTML form control, such as <input> and <textarea>, needs to be labeled accessibly.
- Error situations need to be understood by all users.
- Ensure that your web application can be fully operated with the keyboard only which is exactly same as focus management. 
- Ensure that all functionality exposed through a mouse or pointer event can also be accessed using the keyboard alone.
- Provide a mechanism to allow users to skip past navigation sections in your application as this assists and speeds up keyboard navigation.

In this article we will try to discuss how we can manage focus in our react app.

### Focus Management in React

Keyboard focus refers to the current element in the DOM that is selected to accept input from the keyboard. We want to set focus to a particular element in react component, when after the deletion of particular element or perhaps after form submission or after component first mounts.

**Targeting our elements**

To set focus to our target element in React, we need to use  React's [useRef](https://reactjs.org/docs/hooks-reference.html#useref) hook.

1) Add a import statement in your react component. so that it includes `useRef`:

```jsx
import React, { useRef} from "react";
```

2) create a new constants in the component that has the target element. Something like below :

```jsx
const targetELementRef = useRef(null);
```
The ref has a default value of null because it will not have value until we attach the ref to target element to focus.

3) we'll add an attribute of ref to target element, and set its values to the ref objects that we added above. Let suppose you want to focus input element when component first mounts. Than the input component should be updated like this:

```jsx
import React, { useRef } from 'react';
const CustomTextInput = () => {
    const targetELementRef  = useRef(null);
    return (
        <div>
            <input ref={targetELementRef} />
        </div>
    );
};
```

`Note: ` Some html elements are not usually focusable like header e.g. `<h2>` . But we can make any element programmatically focusable by adding the attribute `tabindex="-1"` to it.

4) setting focus to our target input element using `useEffect()` hook.

`useEffect()` hooks runs after React renders a given component. This make sense in our situation because we don't want browser to focus the element if the component itself is not yet rendered.

- Change the import statement of the component again to add `useEffect`. e.g.

```jsx
import React, { useEffect, useRef, useState } from "react";
```

- Now add the following `useEffect` hook to the component:

```jsx
useEffect(() => {
    targetELementRef.current.focus();
}, []);
```

The second value in the `useEffect` is an empty array. Because we want to focus input element when the component first mount, we have used an empty array. It simply tells React that your effect doesn't depend on any values from props or state, so it never needs to re-run.

But if we want to focus when after the deletion of particular element or perhaps after form submission. We can pass the Some value in the props and update the useEffect as follows:

```jsx
useEffect(() => {
    targetELementRef.current.focus();
}, [someValue]);
```

so the final code should updated like this:

```jsx
import React, { useRef } from 'react';
const CustomTextInput = (props) => {

    const targetELementRef  = useRef(null);

    useEffect((props.dependedValue) => {
        targetELementRef.current.focus();
    }, [someValue]);

    return (
        <div>
            <input ref={targetELementRef} />
        </div>
    );
};
```

At last if you are stuck with a problem that there is no target element to focus, it can happen if you delete an list item and there are no more list items to focus. In that case you can focus the list heading by making list heading focusable using `tabindex="-1" on the list heading or you can move the focus to next actionable item. 

References
- ["Accessibility in React" on mdn](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility)