Interaction to Next Paint (INP) replaced First Input Delay as Google's responsiveness Core Web Vital in March 2024. Unlike FID which measured only the first input delay, INP measures the responsiveness of all interactions throughout the page lifecycle. Improving INP requires understanding the browser's event processing model at a deeper level than most performance guides address.
What Is INP?
INP (Interaction to Next Paint) is a Core Web Vital metric that measures the latency of a page's response to user interactions — clicks, taps, and key presses. Specifically, INP measures the time from when the user initiates an interaction to when the next frame is painted to the screen reflecting that interaction's visual response. INP reports the worst-case interaction latency observed during the page's lifetime (with some outlier exclusion for long sessions).
Anatomy of an INP Interaction
An INP measurement has three phases: input delay, processing time, and presentation delay.
Core INP Optimisation Techniques
1. Break Up Long Tasks
The most common INP problem is long tasks on the main thread that delay event handler execution. The browser cannot process input events while a JavaScript task is running. Use scheduler.yield() (Chrome 115+) or the setTimeout(0) pattern to break long synchronous operations into smaller chunks, yielding control back to the browser between chunks:
// Modern approach using scheduler.yield()
async function processLargeList(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
// Yield to browser every 50 items
if (i % 50 === 0) {
await scheduler.yield();
}
}
}
// Fallback for browsers without scheduler.yield()
function yieldToMain() {
return new Promise(resolve => setTimeout(resolve, 0));
}
2. Defer Non-Critical Work
Move work that doesn't need to happen synchronously in response to an interaction out of the event handler. Analytics tracking, logging, non-critical state updates, and secondary UI updates can be deferred using requestIdleCallback(), requestAnimationFrame(), or setTimeout():
button.addEventListener('click', (event) => {
// Critical: update UI immediately
updateCartUI(item);
// Defer: analytics can wait
requestIdleCallback(() => {
trackAddToCart(item);
});
// Defer: server sync can happen asynchronously
queueMicrotask(() => {
syncCartToServer(item);
});
});
3. Minimise DOM Size and Layout Thrashing
Large DOM trees increase rendering time during the presentation delay phase. Layout thrashing — alternating between reading layout properties and writing DOM changes — forces the browser to recalculate layout synchronously, dramatically extending presentation delay. Read all layout properties first, then apply all DOM changes in a single batch.
element.style.height = element.offsetHeight + 10 + 'px' — reading offsetHeight forces layout; then the style.height write invalidates layout again. In a loop, this is catastrophic for INP. Always read all layout values first, store them, then write all style changes.
4. Use CSS for Animations Instead of JavaScript
CSS animations and transitions that only affect transform and opacity run on the compositor thread, separate from the main thread — they do not block event processing. JavaScript-driven animations that modify layout properties (width, height, top, left) run on the main thread and compete with event handler execution.
Framework-Specific INP Optimisation
| Framework | Common INP Issue | Optimisation |
|---|---|---|
| React | Synchronous re-renders on every interaction | useDeferredValue, startTransition for non-urgent updates |
| React | Large component trees re-rendering | React.memo, useMemo, code splitting with React.lazy |
| Vue | Watchers triggering expensive computed re-computation | Mark non-reactive data with shallowRef/markRaw |
| Angular | Zone.js change detection on every event | OnPush strategy, NgZone.runOutsideAngular for non-UI work |
| Next.js | Heavy hydration blocking interactions | Partial hydration, React Server Components, Suspense boundaries |
Measuring and Debugging INP
import { onINP } from 'web-vitals'. Log interactions above your budget to your analytics tool. INP reports need real user data — lab measurements do not capture the full distribution of interactions.