Stephan Miller Stephan is a full-stack web and mobile developer with over 16 years of experience.

How to autofocus using React Hooks

4 min read 1324

React Logo

Autofocus can make your app more convenient for users. For example, instead of clicking into a field before typing, they can immediately start typing as soon as a form loads. If they are dealing with a large form, users can tab through the rest of the fields after that, all the way down to the submit button, and hit enter without ever touching their mouse.

In this article, we’ll look at how to add autofocus to React input fields. Then, we will make our code reusable by turning what we wrote into a React Hook.

What are React Hooks?

I have to admit I did little with React Hooks when they first came out. I used them when they were there and seemed like a good solution, but I never wrote my own Hooks at first. For me, it was yet another new thing to learn, and I could only ask myself, “Who needs that when we already have stuff that works?”

That was until I had three React components that had different JSX, but the rest of the code was basically the same, so it was copied and pasted. That bothered me. Here, I would usually create a custom class for this functionality if I was using class components, but that didn’t feel right when all of my components were functional.

So, I looked into creating a React Hook, and what I learned was that a Hook is simply a function you create that accepts values and returns other values. In other words, it’s a plain function with a special name so you can organize your code, put all of your “Hooks” together in the same folder, and have less duplicate code. The concept and name of “React Hooks” scared me away for a while because I thought it indicated some special type of functionality, like a thunk or a saga.

You can also use the official definition from React:

Hooks are functions that let you “hook into” React state and lifecycle features from function components.

But I think this definition limits you when thinking of things you could use them for. So, let’s cover the ways you implement autofocus in React, then turn the autofocus functionality into a Hook.

Autofocusing fields with React

There are a few ways to autofocus a React input field.

The autoFocus prop

You can use the autoFocus prop.

const Form = () => {
  return (
    <form>
      <label>
        Email
        <input name="email" type="email" autoFocus />
      </label>
      <label>
        Password
        <input name="email" type="email" />
      </label>
      <button type="submit">Login</button>
    </form>
  );
};
export default Form;

This will work, but there is a caveat that we will get to. In this case, remember to use autoFocus, not autofocus. If you use autofocus instead, React will never actually set the autofocus DOM attribute.



Input for Email

Each browser has different rules when it comes to how this attribute works. Because of these inconsistencies, React calls focus() on the element when it mounts.

But it doesn’t always work. If you add React to an existing application and render a component into a detached element, React will call focus() before the browser is ready, and the input will not be focused when it gets added to the DOM. So, instead of depending on React to call focus() on the input, we are going to do it ourselves.

Autofocusing with useCallback()

The first way we can get more control over autofocus is with the useCallback() Hook. Here is the same form with our new code:

import React, { useCallback } from "react";

const Form = () => {
  const emailInput = useCallback((inputElement) => {
    if (inputElement) {
      inputElement.focus();
    }
  }, []);

  return (
    <form>
      <label>
        Email
        <input name="email" type="email" ref={emailInput} />
      </label>
      <label>
        Password
        <input name="email" type="email" />
      </label>
      <button type="submit">Login</button>
    </form>
  );
};
export default Form;

The useCallback() Hook returns a memoized callback. It accepts two parameters. The first is the function that you want to run, and the second is the array of values that running the function is dependent on. We have an empty array for that parameter, meaning this function will run only once when the component renders.

When the form component renders, the reference for the email input will be set. This executes the function we have in the useCallback() Hook, and that function calls focus() on the input.

Autofocusing using React useRef()and useEffect() Hooks

We can also get the same functionality with the useRef() and useEffect() React Hooks. Here is the same form using these Hooks:

import React, { useRef, useEffect } from "react";

const Form = () => {
  const emailInput = useRef(null);

  useEffect(() => {
    if (emailInput.current) {
      emailInput.current.focus();
    }
  }, []);

  return (
    <form>
      <label>
        Email
        <input name="email" type="email" ref={emailInput} />
      </label>
      <label>
        Password
        <input name="email" type="email" />
      </label>
      <button type="submit">Login</button>
    </form>
  );
};
export default Form;

The useEffect() Hook will tell React that you need your component to do something after it renders. It accepts two parameters. The first is the function that you want to run, and the second is a dependency array that functions the same as it did in useCallback().

The useRef() Hook does for functional components what createRef() did for class-based components. This Hook creates a plain JavaScript object that you can pass to an element to keep a reference of it. This reference can be accessed through the current property of the object.

So, in the code above, we create a reference to the email field. Then, when the component renders, we call focus() on the email field using the current property on the reference object.

It’s pretty simple code, but if you have a lot of forms that use autofocus, it’s much cleaner to turn this code into a Hook so you can reuse it.


More great articles from LogRocket:


Turning our autofocus functionality into a React Hook

Because we have come up with two ways to autofocus an input in React, we can create two versions of our useAutoFocus() Hook. The first version will use useCallback().

import { useCallback } from "react";

const useAutoFocus = () => {
  const inputRef = useCallback((inputElement) => {
    if (inputElement) {
      inputElement.focus();
    }
  }, []);

  return inputRef;
};

export default useAutoFocus;

The second version uses useRef() and useEffect().

import { useRef, useEffect } from "react";

const useAutoFocus = () => {
  const inputRef = useRef(null);

  useEffect(() => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  }, []);

  return inputRef;
};

export default useAutoFocus;

All we did for both versions of this Hook was remove the autofocus functionality from the form itself and move it into its own file.

The code is essentially the same. In the first block, we return the callback function we created. In the second, we return the ref. We can use either with the form component.

import React from "react";
import useAutoFocus from "../hooks/useAutoFocus";

const Form = () => {
  const emailInput = useAutoFocus();

  return (
    <form>
      <label>
        Email
        <input name="email" type="email" ref={emailInput} />
      </label>
      <label>
        Password
        <input name="email" type="email" />
      </label>
      <button type="submit">Login</button>
    </form>
  );
};
export default Form;

Here, we can import either version of our useAutoFocus() Hook that contains the autofocus functionality and execute it to get the reference it created. Then, we use the reference on the email field. We get this result:

Autofocus in React Email and Password Fields

Conclusion

We found three ways to autofocus a field in React and we turned two of those methods into Hooks. Now, instead of copying and pasting code everywhere, we have a Hook we can reuse. You can find all of the code used for this article in this CodeSandbox. Hopefully, you see how simple and useful custom React Hooks can be and start creating your own.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Stephan Miller Stephan is a full-stack web and mobile developer with over 16 years of experience.

Leave a Reply