Back to all notes
useImperativeHandle : Expose Methods from Child to Parent
When refs aren’t enough, selectively expose imperative methods from a child component.
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
- Inside the child, create a local ref to the focusable element.
- Call
useImperativeHandle(ref, () => ({ focusInner() { /* focus */ } })). - In the parent, keep a ref to the child and call
ref.current.focusInner(). - 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();