React useInsertionEffect — CSS-in-JS Style Injection
Understand useInsertionEffect for CSS-in-JS library authors. Covers when it runs, why it exists, comparison with useLayoutEffect, and practical examples of style tag injection.
Detailed Explanation
Style Injection with useInsertionEffect
useInsertionEffect is a specialized hook designed for CSS-in-JS library authors. It fires before DOM mutations and before useLayoutEffect, ensuring styles are available when layout effects read the DOM.
Execution Order
useInsertionEffect -> DOM mutation -> useLayoutEffect -> Paint -> useEffect
Why It Exists
CSS-in-JS libraries like styled-components, Emotion, and Stylex need to inject <style> tags into the document. Before useInsertionEffect, they used useLayoutEffect, which ran after DOM mutations. This meant there was a brief window where DOM nodes existed without their styles, causing incorrect measurements in other useLayoutEffect calls.
Example: Simple CSS Injection
let styleCache = new Map<string, HTMLStyleElement>();
function useCSS(rule: string) {
useInsertionEffect(() => {
if (styleCache.has(rule)) return;
const style = document.createElement("style");
style.textContent = rule;
document.head.appendChild(style);
styleCache.set(rule, style);
return () => {
document.head.removeChild(style);
styleCache.delete(rule);
};
}, [rule]);
}
Restrictions
- You cannot update state from inside useInsertionEffect
- Refs are not attached yet when it runs
- You cannot read or manipulate DOM nodes (they have not been created yet)
- This hook is meant for library authors, not application code
Who Should Use This Hook
If you are building a CSS-in-JS library or a design system framework that dynamically injects styles, useInsertionEffect is the correct timing hook. Application developers should never need to call this hook directly.
Use Case
CSS-in-JS library authors use useInsertionEffect to inject style tags before DOM mutations, ensuring styles are available when useLayoutEffect runs measurements. Application developers should not need this hook directly.