Build a custom React hook that lets a component move keyboard focus to one of its elements on demand. Reading and writing the DOM directly is something React usually hides from you, but focus is a case where you genuinely need an imperative escape hatch: an element has to be told "you're focused now," and there's no prop for that. useFocus hands back a ref to attach to a focusable element, plus a focus() function that focuses it whenever you call it.
function useFocus(): [
ref: React.RefObject<HTMLElement>, // attach to a focusable element
focus: () => void, // call to focus that element
];
The hook returns a two-item tuple. ref goes on the element via <input ref={ref} />; focus is a stable function you can call from an event handler.
function SearchBox() {
const [inputRef, focusInput] = useFocus();
return (
<div>
<input ref={inputRef} placeholder="Search…" />
<button onClick={focusInput}>Jump to search</button>
</div>
);
}
// Clicking "Jump to search" moves the cursor into the input.
// Before the element mounts, ref.current is null. Calling focus() then
// must be a safe no-op, not a crash:
const [ref, focus] = useFocus();
focus(); // ref.current is null here — does nothing, throws nothing
focus must be a no-op when nothing is attached. If ref.current is null — the element hasn't mounted yet, or the ref was never placed — calling focus() must do nothing rather than throw.focus must keep a stable identity. Returning a brand-new function each render would break any child that depends on a steady reference (a memoized component, an effect dependency array). The same function reference should survive across renders.tabIndex can receive focus. Focusing a plain <div> with no tabIndex does nothing — that's the DOM's rule, not the hook's concern.