DOM Manipulation with Refs
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()orremoveChild(). - ❌ Do not modify the
innerHTMLortextContent. - ❌ 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.