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.
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.
There are a few ways to autofocus a React input field.
autoFocus
propYou 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.
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.
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.
useRef()
and useEffect()
HooksWe 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.
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:
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.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.