Frontend Development 14 min read

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.

<code>const element = document.getElementById("bla");</code>
<code>element.focus();</code>
<code>element.scrollIntoView();</code>

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.

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

You can assign a ref to any DOM element or component:

<code>return <input ref={ref} />;</code>

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:

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

The parent creates the ref and forwards it:

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

Using forwardRef

Function components don’t have instances, so you must wrap them with

forwardRef

to accept a ref:

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

The parent can then pass the ref directly:

<code><InputField ref={inputRef} /></code>

Creating an imperative API with useImperativeHandle

To expose methods like

focus

and

shake

on a component, use

useImperativeHandle

:

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

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:

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

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.

ReactRefsuseImperativeHandleforwardRefuseRef
KooFE Frontend Team
Written by

KooFE Frontend Team

Follow the latest frontend updates

0 followers
Reader feedback

How this landed with the community

login 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.