Home

Storing Multiple Elements in a Single Ref in React

In some cases, you may want multiple references in a component of unknown quantity. Here’s how you can make it work.

A typical use of the useRef hook is to be able to access the HTML element directly. This is the example from the React docs:

function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}

This unlocks the ability to access native properties and call native functions on that element.

Accounting for Multiple (Unknown) Refs

I often run into a scenario in which I want direct access to elements with a component (like the example above), but I don’t know how many components there will be.

Consider if we had a similar component, but rather than focusing a single text input, the button would tab through a series inputs of unknown quantity. In that case, we might track the active input with a state, and then increment the index with each button click.

Because I don’t know how many inputs there will be, I can’t use useRef directly on each one. The workaround is to store the ref as an array ...

const inputEls = useRef([]);

... and then pass a function when applying the reference.

// An example where `idx` is a known index value
<input ref={(el) => (inputEls.current[idx] = el)} type="text" />

In context, that might look something like this:

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

export function Component(props) {
const [nextIdx, setNextIdx] = useState(0);
const inputEls = useRef([]);

const onButtonClick = (idx) => {
inputEls.current[nextIdx].focus();
// Find the new next index.
setNextIdx(nextIdx + 1 >= props.inputCount ? 0 : nextIdx + 1);
};

return (
<>
{Array(props.inputCount)
.fill()
.map((_, idx) => (
<input
ref={(el) => (inputEls.current[idx] = el)}
type="text"
style={{ display: "block", marginBottom: "0.5rem" }}
/>

))}
<button onClick={onButtonClick}>Tab through inputs</button>
</>
);
}

That leads to this behavior:

Playground

Here’s a playground with this code so you can see it in action.

Let's Connect

Keep Reading

Use a Class Map to Set Dynamic Styles

Components often need to use styling based on property combinations. There are a number of ways to solve this, but only one I’ve found to be the cleanest.

Feb 03, 2023

WTF is React?

A brief introduction to React, along with a list of references for more learning.

Jun 29, 2020

Simple Content Tab with React and Tailwind

The foundation for a tab system begins with a state hook, triggered by clicks on tab elements. View the code snippet and use the playground to see it in action.

May 28, 2022