{"id":"f66io9tdq5w0eh9","title":"Interaction to Next Paint: What INP Measures and How I Fix It","slug":"interaction-to-next-paint-inp-guide","summary":"INP replaced FID as the responsiveness metric that hurts. I trace long tasks on clicks and cut main-thread debt before chasing bytes.","imageUrl":"https://briancrabtree.me/images/journal-interaction-to-next-paint-inp-guide.webp","category":"Performance","date":"2026-06-04T18:00:00.000Z","featured":false,"likes":19,"author":"Brian Crabtree","content":"<h2>INP in plain engineering terms</h2>\n\n<p>Interaction to Next Paint looks at latency from user input to the next frame paint for interactions during the visit. Slow handlers, layout thrash, and competing long tasks show up. A site can have green LCP and miserable INP because JavaScript wakes up on every tap.</p>\n\n<p>Field data from CrUX drives search signals when traffic exists. Lab tools approximate with Total Blocking Time and interaction traces; I use both.</p>\n\n<p>input delay from busy main thread during hero video decode is fixed by deferring video play until interaction or below fold.</p>\n\n<pre><code>button.addEventListener('click', () =&gt; {\n  // defer heavy work — INP measures next paint after interaction\n  requestAnimationFrame(() =&gt; {\n    startTransition(() =&gt; setItems(next));\n  });\n});</code></pre>\n\n<h2>Long tasks and event handlers</h2>\n\n<p>One click spawns synchronous React re-render of a huge tree, chart redraw, and analytics beacon. Break it up: defer non-urgent work with requestIdleCallback or schedule after paint. Virtualize long lists instead of mounting hundreds of DOM nodes on filter change.</p>\n\n<p>Third-party listeners on capture phase add overhead globally. Audit addEventListener count in Performance profiler.</p>\n\n<p>Scheduler.postTask priority hints help chunk work when browser supports it; graceful degrade when not.</p>\n\n<h2>Input delay versus processing</h2>\n\n<p>Heavy main thread at load delays first interaction even if handlers are small later. Defer below-fold JS, split bundles, and avoid immediate hydration of widgets not visible. INP on mobile lab is where I catch Firebase init competing with menu toggle.</p>\n\n<p>Debouncing search input still needs immediate visual feedback; spinners in input adornment beat blocking render.</p>\n\n<p>When I audit performance stacks, Input delay versus processing is where hours disappear if nobody owns the outcome. I write before-and-after notes, attach PSI or waterfall screenshots, and leave the team a three-item follow-up list. Reproducible wins beat toolchain debates in sprint review. If this section matches your bottleneck, send the URL and whether LCP, INP, CLS, or crawl coverage is the pain point.</p>\n\n<h2>Patterns that help</h2>\n\n<p>Passive listeners where preventDefault is not needed. CSS transforms for animations instead of layout properties. Web workers for heavy parsing if unavoidable. Simpler DOM for filters and tabs on marketing pages.</p>\n\n<p>React 19 concurrent features help but do not replace smaller trees. Compiler reduces some memo overhead; it does not remove bad architecture.</p>\n\n<p>Main thread profiling on mid-tier Android via remote debugging is worth the USB cable pain.</p>\n\n<h2>Measuring fixes</h2>\n\n<p>Chrome DevTools Performance: record, click, inspect longest interaction. Lighthouse timespan mode for SPAs. Compare before and after on same device profile, link PSI URLs in client reports.</p>\n\n<p>RUM providers report INP percentiles; I align fixes to p75 not only median happy path.</p>\n\n<p>When I audit performance stacks, Measuring fixes is where hours disappear if nobody owns the outcome. I write before-and-after notes, attach PSI or waterfall screenshots, and leave the team a three-item follow-up list. Reproducible wins beat toolchain debates in sprint review. If this section matches your bottleneck, send the URL and whether LCP, INP, CLS, or crawl coverage is the pain point.</p>\n\n<h2>Business framing</h2>\n\n<p>Sluggish menus and laggy checkout buttons cost revenue. I translate milliseconds to drop-off estimates when analytics exist. Engineering priority follows money, not only SEO blogs.</p>\n\n<p>Marketing hero carousels with autoplay timers fight user swipe for INP. Autoplay off by default is policy.</p>\n\n<p>When I audit performance stacks, Business framing is where hours disappear if nobody owns the outcome. I write before-and-after notes, attach PSI or waterfall screenshots, and leave the team a three-item follow-up list. Reproducible wins beat toolchain debates in sprint review. If this section matches your bottleneck, send the URL and whether LCP, INP, CLS, or crawl coverage is the pain point.</p>\n\n<h2>Start here</h2>\n\n<p>Send a URL and the interaction that feels sticky. I will profile one session and return top three main-thread cuts. INP fixes are often smaller than redesigns and larger than image compression alone.</p>\n\n<p>I document interaction targets in perf budget same as LCP element identification in runbook.</p>\n\n<p>When I audit performance stacks, Start here is where hours disappear if nobody owns the outcome. I write before-and-after notes, attach PSI or waterfall screenshots, and leave the team a three-item follow-up list. Reproducible wins beat toolchain debates in sprint review. If this section matches your bottleneck, send the URL and whether LCP, INP, CLS, or crawl coverage is the pain point. For a related angle I keep coming back to, see <a href=\"/journal/why-pagespeed-scores-change-every-run/\">Why PageSpeed Scores Change Every Run (And What to Fix First)</a>.</p>","tags":["inp","core-web-vitals","javascript"],"views":49}