Skip to main content

Refs

React allows you to grab the instance of an element or component with refs.

Refs with the useRef hook

Inside a component, refs are created with the useRef hook:

1import {useRef} from 'react';2import * as React from 'react';3
4component MyComponent() {5  const buttonRef = useRef<null | HTMLButtonElement>(null);6  return <button ref={buttonRef}>Toggle</button>;7}

Note that useRef wraps the ref value in an object with a current property. This must be reflected in the type of anything accepting the ref value.

The type useRef returns is React.RefObject<T>. Use it to annotate anything that accepts the ref object, such as a helper that reads current:

1import {useRef} from 'react';2import * as React from 'react';3
4function focusInput(ref: React.RefObject<null | HTMLInputElement>) {5  if (ref.current != null) {6    ref.current.focus();7  }8}9
10component MyComponent() {11  const inputRef = useRef<null | HTMLInputElement>(null);12  return <input ref={inputRef} onClick={() => focusInput(inputRef)} />;13}

Reading ref.current

The current property starts out null and is only populated after the element mounts, so its type includes null. Refine it with a != null check before using it:

1import {useRef} from 'react';2import * as React from 'react';3
4component MyComponent() {5  const inputRef = useRef<null | HTMLInputElement>(null);6
7  const focusInput = () => {8    inputRef.current.focus(); // ERROR: `current` may be nullincompatible-useCannot call inputRef.current.focus because property focus is missing in null [1].9    if (inputRef.current != null) {10      inputRef.current.focus(); // OK: refined to non-null11    }12  };13
14  return <input ref={inputRef} onClick={focusInput} />;15}

Accepting a ref with React.RefSetter

To let a parent attach a ref to your component, add a ref parameter typed with React.RefSetter<T>, where T is the instance you expose. With Component Syntax this is just another parameter:

1import {useRef} from 'react';2import * as React from 'react';3
4component FancyInput(ref: React.RefSetter<HTMLInputElement>) {5  return <input ref={ref} />;6}7
8component Form() {9  const inputRef = useRef<null | HTMLInputElement>(null);10  return <FancyInput ref={inputRef} />;11}

You write the ref parameter the same way regardless of the React version you target; behind the scenes Component Syntax compiles it to a React.forwardRef call (React 18) or a plain ref prop (React 19). The ref must be a direct parameter, not nested in a rest parameter. See Ref Parameters for the full explanation.

Callback refs

Instead of a ref object, you can pass a function as a ref. React calls it with the element instance when it mounts, and with null when it unmounts, so the parameter type is T | null:

1import * as React from 'react';2
3component MyComponent() {4  const setButtonRef = (button: HTMLButtonElement | null) => {5    if (button != null) {6      button.focus();7    }8  };9
10  return <button ref={setButtonRef}>Toggle</button>;11}

A ref parameter typed React.RefSetter<T> accepts both a ref object and a callback ref, so a component written with the pattern above works with either.

Deriving ref types

To name the type behind a ref without spelling it out, Flow provides two utilities:

  • React.ElementRef<typeof Component> gives the instance type a component exposes (for example HTMLInputElement for an 'input', or a class instance for a class component).
  • React.RefOf<Component> gives the type of the current field on a component's ref prop, or void if it has none.

See Also