How to use forwardRef in Typescript

2 min read

Update: Starting in React 19 (opens in a new tab), passing ref as a prop for function components is available. See updated tutorial.

Sometimes we need to pass a ref to another component as a prop (e.g., to access DOM node of a component from a parent component). In these situations, we can use forwardRef because the ref prop is handled differently than normal props. Let's see its usage in TypeScript.

To illustrate this concept, let's create a simple app with an input field and a button. The button will be a separate component, and when clicked, the input field should be focused using its ref. Basically, we control input field's DOM node from the button component.

Code

Inside App.tsx: we add an input and a button component. The ref is created using useRef hook and we can specify the type of the ref. In this case, it is an HTMLInputElement. The button component will be a separate component and we will pass the ref to it.

// App.tsx
import { ButtonComponent } from './ButtonComponent'
 
import { useRef } from 'react'
 
export default function App() {
  const ref = useRef<HTMLInputElement>(null)
 
  return (
    <div className="App">
      <h2>forwardRef example with TypeScript</h2>
      <p>Click to the button to focus on the input</p>
      <ButtonComponent title="Click here to focus the input" ref={ref} />
      <br />
      <input placeholder="Click the button to focus here" ref={ref} />
    </div>
  )
}

Code for ButtonComponent.tsx: we use forwardRef to pass the ref to the button component. The first argument is the type of the ref (HTMLInputElement) and the second argument is the type of the props (PropsType). In this case, the ref is an HTMLInputElement and the props are title which is a string.

// ButtonComponent.tsx
import { forwardRef, RefObject } from 'react'
 
type PropsType = {
  title?: string
}
 
const ButtonComponent = forwardRef<HTMLInputElement, PropsType>(
  ({ title }, ref) => {
    const onClickHandler = () => {
      const inputRef = ref as RefObject<HTMLInputElement>
      inputRef.current?.focus()
    }
 
    return <button onClick={onClickHandler}>{title}</button>
  }
)
 
export { ButtonComponent }

The reason why we need to cast the ref to RefObject inside onClick() is that there are two different kinds of refs. One is an object with a current property and the another is a ref callback (for advanced use cases). So, we need to cast it to RefObject to access the current property. For more information check this Stackoverflow answer (opens in a new tab).

Demo

View on CodeSandbox (opens in a new tab)

2024 © Bekzodjon Norkuziev.RSS