diagram.mmd — flowchart
DOM Update Lifecycle flowchart diagram

The DOM update lifecycle describes the chain of events that occurs in the browser from the moment JavaScript mutates the DOM or CSS to the moment the updated frame is visible on screen.

Every mutation — setting element.textContent, toggling a class, adjusting an inline style — marks affected nodes as dirty in the browser's internal rendering state. The browser does not repaint immediately; instead, it batches changes and processes them synchronously at the end of the current JavaScript task, before yielding control back to the event loop. This batching is intentional: multiple mutations to the same element in a single task result in only one reflow, not one per mutation.

Once the JavaScript call stack is empty, the browser enters the style recalculation phase, re-evaluating which CSS rules apply to each dirty node. If geometry is affected (width, height, margin, padding, position), a layout / reflow pass recalculates the size and position of affected nodes and potentially their ancestors and descendants. The scope of a reflow depends on which CSS properties changed — modifying font-size on the can trigger a full-page reflow, while changing color on a leaf node is much cheaper.

After layout, painting records the updated draw commands for dirty layers, and compositing merges all layers into the final frame. The total time from mutation to painted frame must fit within 16.67 ms (one frame at 60 fps) to avoid jank. Understanding this lifecycle motivates patterns like batching DOM writes, avoiding forced synchronous layout (reading offsetWidth after a write forces the browser to flush the pending layout immediately), and preferring CSS transform and opacity for animations since they bypass the layout and paint stages entirely and run on the compositor thread.

For framework-level optimizations that reduce the number of raw DOM mutations, see Virtual DOM Diffing and React Rendering Lifecycle. For the full browser pipeline context, see Browser Rendering Pipeline.

Free online editor
Edit this diagram in Graphlet
Fork, modify, and export to SVG or PNG. No sign-up required.
Open in Graphlet →

Frequently asked questions

The DOM update lifecycle is the chain of browser phases — style recalculation, layout (reflow), paint, and composite — that runs after JavaScript mutates the DOM or CSS. The browser batches changes from a single JavaScript task and processes them together at the end of that task before yielding to the event loop.
After a JavaScript task completes, the browser recalculates CSS styles for dirty nodes, then reflows affected elements to compute their new sizes and positions. If only visual properties changed (color, opacity), it skips layout and goes straight to paint. Composite layers are then merged to produce the final frame. The full cycle must fit within 16.67 ms at 60 fps.
A forced synchronous layout (also called layout thrashing) happens when JavaScript reads a geometry property — `offsetWidth`, `getBoundingClientRect`, `scrollTop` — after a write that invalidated layout. The browser must flush the pending layout immediately to return an accurate value, then potentially reflow again when the next write arrives. Repeatedly interleaving reads and writes in a loop multiplies the layout cost by the iteration count.
Reading layout properties inside loops after DOM writes is the most impactful mistake. Others include animating non-compositor properties (triggering layout or paint per frame), making large DOM changes outside a document fragment or batch, and not using `requestAnimationFrame` to synchronize writes with the browser's rendering cycle.
mermaid
flowchart TD A[JavaScript Mutates DOM or Style] --> B[Node Marked Dirty] B --> C{More JS mutations in same task?} C -- Yes --> B C -- No --> D[JS Call Stack Empty] D --> E[Style Recalculation] E --> F{Geometry changed?} F -- Yes --> G[Layout / Reflow] F -- No --> H[Skip Layout] G --> I{Paint needed?} H --> I I -- Yes --> J[Paint — Update Draw Commands] I -- No --> K[Compositor-only Update] J --> L[Composite Layers] K --> L L --> M[New Frame Displayed] style M fill:#22c55e,color:#fff
Copied to clipboard