useImperativeHandle Explained: Exposing a Controlled Component API

Use useImperativeHandle to replace the DOM node exposed through a ref with a custom object, so a parent can call only the methods you allow.

6 min read

useImperativeHandle lets a component replace the DOM node exposed through a ref with a custom object. The parent then sees only the methods you choose, keeping the child's internals private. It is an escape hatch for imperative behavior that cannot be expressed as props.

What it does and when to use it

The Hook is stable and imported from react. In React 19 and later you receive ref as a prop, so you call useImperativeHandle directly instead of going through forwardRef.

ArgumentRole
refThe ref prop received from the parent.
createHandleA function that returns the object to expose.
dependenciesOptional array of reactive values read inside createHandle.

The Hook returns undefined. It works by reassigning what the parent sees when it reads the ref, rather than producing a value you render.

Expose a limited input API

A parent often only needs focus, not the whole input element. Keep the real DOM node in a private ref and expose a single focus method.

App.jsxApp.jsx
import { useRef, useImperativeHandle } from "react";
 
function MyInput({ ref }) {
  const inputRef = useRef(null);
  useImperativeHandle(ref, () => ({
    focus() {
      inputRef.current.focus();
    },
  }), []);
  return <input ref={inputRef} />;
}

The child holds the actual input in inputRef, then exposes only focus through the handle. The parent cannot read the input's style or any other DOM property.

App.jsxApp.jsx
import { useRef } from "react";
 
function Form() {
  const inputRef = useRef(null);
 
  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>Focus</button>
    </>
  );
}

Clicking the button calls the exposed focus method. The empty dependency array tells React to build the handle once, since the methods never change. The parent reads the handle through the same ref object, but only the focus method is reachable.

Expose your own methods

The handle does not have to mirror DOM methods. It can combine several steps under one method name.

App.jsxApp.jsx
import { useRef, useImperativeHandle } from "react";
 
function SearchBox({ ref }) {
  const inputRef = useRef(null);
  useImperativeHandle(ref, () => ({
    focusAndSelect() {
      inputRef.current.focus();
      inputRef.current.select();
    },
  }), []);
  return <input ref={inputRef} />;
}

The child exposes one method that focuses the field and selects its text. The parent never needs to know that two DOM calls are involved.

App.jsxApp.jsx
import { useRef } from "react";
 
function Form() {
  const inputRef = useRef(null);
 
  return (
    <>
      <SearchBox ref={inputRef} />
      <button onClick={() => inputRef.current.focusAndSelect()}>Select</button>
    </>
  );
}

Clicking the button selects the text inside the input. The implementation stays hidden inside SearchBox.

Prefer props over imperative handles

Imperative handles are a last resort. If a behavior can be expressed as a prop, use a prop instead. A Modal should take an isOpen prop rather than expose open and close methods through a ref.

Imperative code is harder to trace than declarative props, because it runs outside the normal data flow. See how to pass refs between components for the plain forwarding alternative.

What to learn next

A ref can be either an object or a function. Continue with callback refs vs object refs.

Rune AI

Rune AI

Key Insights

  • useImperativeHandle(ref, createHandle, dependencies?) customizes the exposed handle.
  • Keep the real DOM node in a separate ref inside the child.
  • The handle exposes only the methods you return.
  • Use it for focus, scroll, and similar imperative actions.
  • Prefer props like isOpen over imperative methods when possible.
RunePowered by Rune AI

Frequently Asked Questions

What does useImperativeHandle return?

It returns undefined. Its job is to change what the parent sees when it reads the ref, not to produce a value.

When should I use useImperativeHandle?

Only for imperative behavior that cannot be expressed as a prop, such as focus, scroll, or a custom action. Prefer props whenever possible.

Do I need forwardRef with useImperativeHandle?

Not in React 19. You receive ref as a prop and pass it directly to useImperativeHandle.

Conclusion

useImperativeHandle swaps the DOM node exposed through a ref for a custom object you control. It keeps a child's internals private while letting a parent call a small set of imperative methods.