An article page is server-rendered React. Field p75 interaction to next paint is 420 ms on mid-range Android and the main thread is busy for roughly 1.9 seconds after the HTML arrives. Three widgets account for most of the client bundle - a comment thread a video player and a recommendation carousel. Fewer than 5% of readers open comments. Which change gets interaction to next paint under 200 ms with the least risk?
Show the full answer Hide the answer
The deciding property
Interaction to next paint is a client CPU metric. The 200 ms p75 threshold for a good rating has been the published bar since interaction to next paint became a Core Web Vital on 12 March 2024, and the 1.9 seconds of main-thread work in the stem is the cause: the browser is re-running component logic for a tree the reader is not touching. The fact that settles the choice is the ratio of interactive surface to read-only surface — an article is almost entirely read-only, and fewer than 1 in 20 readers opens the widget with the largest share of the bundle.
Why this one
Deferring hydration until a widget is interacted with removes its execution from the critical window entirely. The article's text, which is what the reader came for, is static HTML that needed no JavaScript to be correct. A reasonable implementation keeps a placeholder of the right size, registers a capture-phase listener, loads the chunk on the first pointer or focus event, and replays that event — so the first tap pays 200-400 ms and every subsequent one is instant.
What it costs: the first interaction with a deferred widget is slower than it is today, and the code has to handle an interaction that arrives before its handler exists. That is a real engineering cost and it is paid by 5% of readers rather than by all of them.
Why the other options fail
- Edge rendering cuts time to first byte by perhaps 50-150 ms by producing HTML closer to the reader. It changes not one byte of shipped JavaScript, so the main thread is busy for the same 1.9 seconds. It is the right call when first byte dominates largest contentful paint.
- A longer cache time to live improves delivery for the same reason and has the same irrelevance: a cache hit does not execute less code. It is right when origin render time is the bottleneck.
- A framework upgrade buys a constant factor on hydration, which is usually tens of per cent and never an order of magnitude, because hydration cost is proportional to the component tree you hydrate. Shrinking the tree beats speeding up the walk. The upgrade becomes right when you are on a major version with a known regression.
When this is the wrong answer
For an application where nearly everything is interactive — a design tool, a spreadsheet, a trading screen — deferring hydration moves the same cost to the moment the user acts, which is the worst possible moment. There the answer is one hydrated shell plus code splitting by route, and the metric to chase is the long tasks inside the interaction handlers rather than the initial walk.
Common weak answers
- "Replace the carousel with a lighter library." Real and partial: it trims one of three widgets and leaves the structure that will regrow. It becomes the right first move when one dependency is most of the bundle.
- "Add a loading spinner." The page is already painted. The complaint is that it ignores taps.