React Hooks Series

useImperativeHandle

Customise what a parent sees when it holds a ref to your component. Instead of exposing the raw DOM node, you expose a controlled API, only the methods you choose.

01 — What it is

01
The problem it solves

By default, ref on a function component does nothing — function components don't have instances. You need forwardRef to accept a ref, and useImperativeHandle to control exactly what that ref exposes.

This is the escape hatch for imperative behaviour: playing/pausing media, triggering animations, focusing inputs, or toggling internal state from outside the component, without lifting state up.

02
The signature
useImperativeHandle(ref, () => ({
  // only expose what you want the parent to call
  focus() { inputRef.current.focus(); },
  reset() { setValue(""); },
}), [deps]); // optional deps array
Always pair with forwardRef. Without it the ref prop is silently discarded and useImperativeHandle has nothing to attach to.

02 — How to use it

03
The child component

Wrap the component in forwardRef, define the handle interface, and expose only the methods the parent needs.

// 1. Define what the parent can call
export interface ButtonHandle {
  alterToggle: () => void;
}

// 2. Wrap with forwardRef
const Button = forwardRef<ButtonHandle>((_, ref) => {
  const [toggle, setToggle] = useState(false);

  // 3. Expose a controlled API
  useImperativeHandle(ref, () => ({
    alterToggle() {
      setToggle((prev) => !prev);
    },
  }));

  return <button onClick={() => setToggle(p => !p)}>Child button</button>;
});
04
The parent component

The parent creates a ref typed to the handle interface and calls methods on it directly — no props, no callbacks, no lifted state.

const buttonRef = useRef<ButtonHandle>(null);

// Call the child's method from the parent
<button onClick={() => buttonRef.current?.alterToggle()}>
  Trigger from parent
</button>

// Render the child with the ref attached
<Button ref={buttonRef} />

03 — Live demo

ImperativeHandleTutorial — interactive

Click "Trigger from parent" — it calls alterToggle() on the child component through the ref. The child also has its own button that does the same thing internally.

Child component

The parent calls alterToggle() on the child via ref — without prop drilling

04 — When to use it

05
Good vs bad use cases
Good use caseBetter alternative
Focus / scroll / play from parent— this is exactly what it's for
Toggle internal UI state from outside— fine if lifting state is awkward
Sharing business logic upwardMove logic to parent or custom hook
Replacing all prop passingUse props — this hook is an escape hatch
Reach for useImperativeHandle sparingly. Most interactions are better expressed with props and callbacks. It shines for DOM-level control and when you genuinely need to trigger behaviour in a child from an unrelated parent.
That's all the hooks covered in this series. You now have the full mental model — from useState right through to useImperativeHandle.