Now Reading:

Using forwardRef With Generic Components

In React, refs are used to get references to DOM elements or class components. However, when you wrap a functional component, the ref gets lost because it’s not attached to a DOM element.

forwardRef allows your functional components to pass refs down to their children. This is super handy when you’re dealing with components that need to expose a DOM node, or in more complex cases, when passing refs through several layers of components.

The Use Case for forwardRef

Consider this scenario: You’re building a custom Input component that you want to be able to focus programmatically from a parent component. Here’s where forwardRef shines. By using forwardRef, you can directly interact with the input element without breaking any abstraction layers.

Normally, React components do not pass refs to child components by default. For example:


_12
const Input = ({ label }: { label: string }) => {
_12
return (
_12
<label>
_12
{label}
_12
<input />
_12
</label>
_12
);
_12
};
_12
_12
const ref = useRef<HTMLInputElement>(null);
_12
_12
<Input ref={ref} />; // ❌ Error: ref is not a prop of Input!

Since Input is a function component, ref isn't automatically forwarded to the <input> inside.

This is where forwardRef comes in:


_10
const Input = React.forwardRef<HTMLInputElement, { label: string }>(
_10
({ label }, ref) => {
_10
return (
_10
<label>
_10
{label}
_10
<input ref={ref} />
_10
</label>
_10
);
_10
}
_10
);

Now, ref correctly refers to the <input> inside Input.

But what if we need to make Input generic?

Understanding Generic Components

#

So, what are generic components in this context? Generics allow you to create components that can work with a variety of data types. This is especially useful in TypeScript, where you want your components to be flexible without losing type safety.

For example, a component can accept a specific type of props while still being able to interface with different data types. Think of generics as a way to enforce structure while maintaining flexibility.

A Simple Example

Let’s start with a basic Input component that uses both generics and forwardRef.

First, we’ll create a component that accepts a ref and props:


_15
import React, { forwardRef } from 'react';
_15
_15
type InputProps<T> = {
_15
value: T;
_15
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
_15
};
_15
_15
const Input = forwardRef<HTMLInputElement, InputProps<string>>(({ value, onChange }, ref) => (
_15
<input
_15
ref={ref}
_15
value={value}
_15
onChange={onChange}
_15
style={{ padding: '8px', borderRadius: '4px', border: '1px solid #ccc' }}
_15
/>
_15
));

In this code we define a generic type InputProps<T>. Here, T can be any type 🥳

We then utilise forwardRef to pass the ref down to the actual input element.

Using Our Generic Input Component

Now let’s see how we can use this reusable Input component in another file:


_23
import React, { useRef } from 'react';
_23
_23
const App: React.FC = () => {
_23
const inputRef = useRef<HTMLInputElement>(null);
_23
_23
const handleFocus = () => {
_23
inputRef.current?.focus();
_23
};
_23
_23
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
_23
console.log(event.target.value);
_23
};
_23
_23
return (
_23
<div>
_23
<h1>Custom Input Example with forwardRef</h1>
_23
<Input ref={inputRef} value="Hello" onChange={handleChange} />
_23
<button onClick={handleFocus}>Focus Input</button>
_23
</div>
_23
);
_23
};
_23
_23
export default App;

First we create a ref with useRef to interact with the Input component. By clicking the "Focus Input" button, you can see how forwardRef lets us control the underlying input element.

Stay ahead of the pack 🐶

Join the newsletter to get the latest articles and expert advice directly to your inbox.
Totally free, no spam and you can unsubscribe anytime you want!

  • Expert Tips
  • No Spam
  • Latest Updates

I'll never share any of your information with a third party. That's a promise.

forwardRef In The Real World

#

Let’s take this concept and apply it to a more realistic scenario you might encounter in product engineering. Imagine building a custom Select component that allows you to open and focus on it through a button click.

You can implement a similar pattern as shown above. Firstly Create a Select component using forwardRef. then we can Handle focus the same way with refs.


_20
import React, { forwardRef } from 'react';
_20
_20
type SelectProps = {
_20
options: string[];
_20
onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
_20
};
_20
_20
const CustomSelect = forwardRef<HTMLSelectElement, SelectProps>(
_20
({ options, onChange }, ref) => (
_20
<select ref={ref} onChange={onChange}>
_20
{options.map((option) => (
_20
<option key={option} value={option}>
_20
{option}
_20
</option>
_20
))}
_20
</select>
_20
)
_20
);
_20
_20
CustomSelect.displayName = "CustomSelect";

We can use this in our parent component


_19
import React, { useRef } from 'react';
_19
_19
const App: React.FC = () => {
_19
const selectRef = useRef<HTMLSelectElement>(null);
_19
_19
const handleOpen = () => {
_19
selectRef.current?.focus();
_19
};
_19
_19
return (
_19
<div>
_19
<h1>Select Example with forwardRef</h1>
_19
<CustomSelect ref={selectRef} options={['Option 1', 'Option 2']} onChange={() => {}} />
_19
<button onClick={handleOpen}>Focus Select</button>
_19
</div>
_19
);
_19
};
_19
_19
export default App;

Tips For Using Refs

#

Always extend HTMLElement in generics without T extends HTMLElement, TypeScript won’t enforce valid ref types.

Use ComponentPropsWithRef<T> for props. This ensures the correct attributes are passed based on the HTML element type.

To help with with debugging in React DevTools, explicitly Set the displayName.

Conclusion

#

And there you have it! We’ve explored how to effectively use forwardRef with generic components in React. You learned how to create reusable components while ensuring they are type-safe with TypeScript. This approach not only simplifies code but also enhances user experience by enabling better control over form elements.

Halpy coding,

DANNY

Quiz Time

#

Reinforce Your Learning

One of the best ways to reinforce what your learning is to test yourself to solidify the knowlege in your memory.
Complete this 5 question quiz to see how much you remember.

1) What is the main purpose of using forwardRef in React
file under:
React

Thanks alot for your feedback!

The insights you share really help me with improving the quality of the content here.

If there's anything you would like to add, please send a message to:

[email protected]

Was this article this helpful?

D is for danny

About the author

Danny Engineering

A software engineer with a strong belief in human-centric design and driven by a deep empathy for users. Combining the latest technology with human values to build a better, more connected world.

Gobacktothetop

Made with 🥰 in 🏴󠁧󠁢󠁥󠁮󠁧󠁿

©2025 All rights reserved.