DOM Manipulation with Refs

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

DOM Manipulation with Refs

While React encourages a declarative approach, certain tasks require imperative DOM manipulation. When you attach a ref to a JSX element, React gives you access to the underlying DOM node, allowing you to call standard DOM APIs.

Common Use Cases

1. Managing Focus

If you have a modal that opens, you might want to immediately focus the first input field inside it for accessibility.

function Modal() {
  const inputRef = useRef(null);

  useEffect(() => {
    // When the component mounts, immediately focus the input
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} placeholder="Enter your name" />;
}

2. Scrolling to an Element

You can use refs to implement “scroll to top” buttons, or to scroll a specific element into view when a user clicks a navigation link.

function ScrollGallery() {
  const imageRef = useRef(null);

  const scrollToImage = () => {
    // Use the native DOM API to scroll
    imageRef.current.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    });
  };

  return (
    <div>
      <button onClick={scrollToImage}>View Image 5</button>
      <div className="gallery">
        {/* ... other images */}
        <img ref={imageRef} src="/image-5.jpg" alt="Target" />
      </div>
    </div>
  );
}

3. Measuring Elements

If you need to know the width, height, or position of an element to render something else (like positioning a tooltip perfectly above a button), you use a ref to read getBoundingClientRect().

function Tooltip({ children }) {
  const containerRef = useRef(null);

  useEffect(() => {
    const { width, height } = containerRef.current.getBoundingClientRect();
    console.log(`Element is ${width}px by ${height}px`);
  }, []);

  return <div ref={containerRef}>{children}</div>;
}

What NOT to do with DOM Refs

React manages the DOM. If you use a ref to manually change things that React is also trying to manage, your app will crash or behave unpredictably.

Do not use refs to change the DOM structure:

  • ❌ Do not appendChild() or removeChild().
  • ❌ Do not modify the innerHTML or textContent.
  • ❌ Do not manually add or remove CSS classes that are also controlled by React state.
function BadComponent() {
  const divRef = useRef(null);

  const hideDiv = () => {
    // ❌ REACT WILL GET CONFUSED! 
    // React's Virtual DOM thinks this div still exists.
    divRef.current.remove(); 
  };

  return (
    <div>
      <div ref={divRef}>I am managed by React</div>
      <button onClick={hideDiv}>Hide</button>
    </div>
  );
}

Instead of manually removing the node with a ref, you should use state to conditionally render it: {isVisible && <div>I am managed by React</div>}.

Interview Questions

Q: Is it safe to manipulate the DOM directly using a ref?
A: Yes, for non-destructive actions like calling .focus(), .scrollIntoView(), or measuring sizes. However, you should NEVER use a ref to actively add, remove, or modify DOM nodes (like changing innerHTML) that React is actively managing, as this will crash React’s reconciliation engine.