How to Implement useInsertionEffect in React

In this article, you will learn how to implement the useInsertionEffect hook in React. We will cover its specific use case—injecting dynamic CSS-in-JS styles into the DOM before layout effects trigger—explain why it is crucial for performance, and provide a practical code example demonstrating its usage.

What is useInsertionEffect?

useInsertionEffect is a React hook introduced in React 18. It is designed exclusively for authors of CSS-in-JS libraries. The hook fires synchronously before any layout effects (useLayoutEffect) run and before the browser paints the screen. This timing allows you to inject <style> elements into the document head before React calculates the layout of the DOM.

Why Use It Instead of useLayoutEffect?

Using useLayoutEffect or useEffect to inject styles dynamically causes performance issues. If you insert <style> tags during those phases, the browser is forced to recalculate the layout (a process known as “style recalc” or “reflow”) multiple times. By using useInsertionEffect, you ensure that styles are injected before React does any layout passes, preventing expensive layout recalculations.

How to Implement useInsertionEffect

To implement useInsertionEffect, import it from React and use it to insert your style rules. Note that you do not have access to refs inside this hook, and it should not be used for general side effects like fetching data or updating state.

Here is a practical implementation example:

import React, { useInsertionEffect } from 'react';

// Helper function to insert styles into the document head
function insertStyleRule(rule) {
  const style = document.createElement('style');
  style.textContent = rule;
  document.head.appendChild(style);
}

function MyStyledComponent() {
  useInsertionEffect(() => {
    const rule = `.dynamic-btn { background-color: #0070f3; color: white; padding: 10px; border: none; }`;
    insertStyleRule(rule);
  }, []); // Empty dependency array ensures this runs once when the component mounts

  return <button className="dynamic-btn">Click Me</button>;
}

export default MyStyledComponent;

Hook Execution Order

To understand exactly when this hook runs, here is the chronological order of React’s effect hooks:

  1. useInsertionEffect: Runs before DOM mutations and layout calculations. Best for dynamic style injection.
  2. useLayoutEffect: Runs after DOM mutations but before the browser paints. Best for reading DOM layout (like measuring element size).
  3. useEffect: Runs after the browser has painted the screen. Best for general side effects like data fetching and event listeners.