Master React Refs: From DOM Access to Imperative APIs

Learn how to use React refs—including useRef, forwardRef, and useImperativeHandle—to access DOM elements, create custom imperative APIs, and build interactive forms with focus and shake effects, while understanding best practices for when to employ refs versus state or props.

KooFE Frontend Team
KooFE Frontend Team
KooFE Frontend Team
Master React Refs: From DOM Access to Imperative APIs
This article is translated from “Refs in React: from access to DOM to imperative API”.

React abstracts DOM manipulation, but sometimes you need to access real DOM elements.

Using useRef to access DOM

Example of focusing an empty field, etc.

const element = document.getElementById("bla");
element.focus();
element.scrollIntoView();

Typical scenarios for using native DOM API in React:

Manually focusing an element after render, such as an input field.

Detecting clicks outside a popup component.

Scrolling to an element that appears on screen.

Measuring component size and bounds to position tooltips.

React provides refs as a more powerful way to access elements without IDs.

A ref is a mutable object created with useRef. It holds a current property that can store any value, including a DOM node.

const Component = () => {
  const ref = useRef(null);
  return ...;
}

You can assign a ref to any DOM element or component: return <input ref={ref} />; When the component mounts, ref.current points to the input element, similar to getElementById.

Passing ref as a prop

Extract input fields into a separate component and pass a ref from the parent:

const InputField = ({ onChange, label }) => (
  <>
    {label}<br/>
    <input type="text" onChange={e => onChange(e.target.value)} />
  </>
);

The parent creates the ref and forwards it:

const Form = () => {
  const inputRef = useRef(null);
  return (
    <>
      <InputField inputRef={inputRef} />
      <button onClick={onSubmitClick}>Submit</button>
    </>
  );
};

Using forwardRef

Function components don’t have instances, so you must wrap them with forwardRef to accept a ref:

const InputField = forwardRef((props, ref) => (
  <input ref={ref} />
));

The parent can then pass the ref directly:

<InputField ref={inputRef} />

Creating an imperative API with useImperativeHandle

To expose methods like focus and shake on a component, use useImperativeHandle:

useImperativeHandle(apiRef, () => ({
  focus: () => inputRef.current.focus(),
  shake: () => setShouldShake(true),
}), []);

The parent can call apiRef.current.focus() or apiRef.current.shake() without knowing the internal implementation.

Alternative without useImperativeHandle

You can assign the API object directly in an effect:

useEffect(() => {
  apiRef.current = {
    focus: () => inputRef.current.focus(),
    shake: () => setShouldShake(true),
  };
}, [apiRef]);

Both approaches give a clean way to implement command‑style actions while keeping refs as an emergency escape hatch, not a replacement for state or props.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendReactrefsuseImperativeHandleforwardRefuseRef
KooFE Frontend Team
Written by

KooFE Frontend Team

Follow the latest frontend updates

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.