Back to all notes

useImperativeHandle : Expose Methods from Child to Parent

When refs aren’t enough, selectively expose imperative methods from a child component.

2 min read

Introduction

useImperativeHandle lets a child component expose specific methods to its parent through a ref. It’s a controlled escape hatch for cases where props and events aren’t enough.

Why this matters

Most of the time, data should flow down and events up. Occasionally you need an imperative escape hatch—like focusing an input. useImperativeHandle lets the child expose specific methods to its parent via a ref.

The problem

Parents sometimes need to call a method on a child (e.g., focus). Without an imperative handle, you either:

  • Thread callback props down several layers, or
  • Toggle state to force focus, causing re-renders.

Inefficient approach

Prop‑drilling focus handlers or relying on autoFocus toggles is fragile:

import { useState } from "react";

function App() {
  const [shouldFocus, setShouldFocus] = useState(false);
  return (
    <div>
      <h1>useImperativeHandle</h1>
      <input autoFocus={shouldFocus} placeholder="Click button to focus me" />
      <button onClick={() => setShouldFocus(true)}>Focus Input</button>
    </div>
  );
}

export default App;

Downsides:

  • Causes extra renders just to focus.
  • Hard to reuse across different inputs.
  • Breaks if component structure changes.

The solution

Expose a focusInner method from a custom input.

import { useRef, useImperativeHandle, forwardRef } from "react";

const CustomInput = forwardRef(function CustomInput({ ...rest }, ref) {
  const localRef = useRef();
  useImperativeHandle(
    ref,
    () => ({
      focusInner() {
        localRef.current.focus();
      },
    }),
    [],
  );
  return <input ref={localRef} {...rest} />;
});

function App() {
  const inputRef = useRef();
  const handleFocus = () => {
    inputRef.current.focusInner();
  };
  return (
    <div>
      <h1>useImperativeHandle</h1>
      <CustomInput ref={inputRef} placeholder="Click button to focus me" />
      <button onClick={handleFocus}>Focus Input</button>
    </div>
  );
}

export default App;

Step-by-step

  1. Inside the child, create a local ref to the focusable element.
  2. Call useImperativeHandle(ref, () => ({ focusInner() { /* focus */ } })).
  3. In the parent, keep a ref to the child and call ref.current.focusInner().
  4. Avoid exposing anything except what the parent actually needs.

Tips

  • Expose the minimal surface area—don’t leak internal details.
  • Avoid mixing controlled inputs with imperative APIs; pick one approach.
  • Prefer composition and props; use imperative handles as a last resort.

Knowledge base

Problem snippet:

<input autoFocus={shouldFocus} />
<button onClick={() => setShouldFocus(true)}>Focus</button>

Solution snippet:

const inputRef = useRef();
<CustomInput ref={inputRef} />
inputRef.current.focusInner();