Improving INP in React Apps: A Practical Core Web Vitals Guide

Improving INP in React Apps: A Practical Core Web Vitals Guide — cover image

INP Replaced FID: What Changed and Why It Matters

For years, developers optimized First Input Delay (FID), a metric that only measured the delay before the browser began handling a user's first interaction. In 2024, Google replaced it with Interaction to Next Paint (INP) as a Core Web Vital. INP looks at the responsiveness of all clicks, taps, and key presses during a visit and reports a value close to the slowest one. A page can pass FID easily and still feel sluggish, which is exactly the gap INP was designed to expose.

For React apps, INP is where real-world pain tends to show up. Heavy components, large lists, expensive state updates, and third-party scripts all compete for the same main thread. This guide explains how to measure INP properly, find the interactions that hurt, and fix them without rewriting your product.

If you are also thinking about overall speed targets, our article on performance budgets for web apps in CI pairs well with the techniques below.

What INP Actually Measures

An interaction has three phases, and INP counts all of them:

Google's published guidance classes INP of 200 milliseconds or less as good, between 200 and 500 milliseconds as needing improvement, and above 500 milliseconds as poor, measured at the 75th percentile of real page loads. Those thresholds come from Google's Web Vitals documentation, so check it for the latest figures.

Lab Data vs. Field Data

INP is fundamentally a field metric. It depends on what real users do, on their devices, and on how long they stay on the page. Lighthouse in a lab cannot fully reproduce it, although Total Blocking Time offers a rough proxy.

Where to get real INP numbers

Test on mid-range hardware. Many Indian users browse on devices that are several times slower than a developer laptop, so a page that feels instant on your machine can be sluggish for a large share of your audience.

Real-World Example: A Dashboard That Felt Slow

Consider an illustrative case. A SaaS analytics dashboard built in React lets users filter a table of several thousand rows. Each keystroke in the search box triggers a state update that re-renders the entire table, recalculates sorted data, and updates several charts. On a fast laptop, nothing seems wrong. On a mid-range phone, typing stutters, and field data shows a poor INP for the search input.

The team could trace this with the Performance panel and find one long task per keystroke. A sensible fix sequence might be: debounce the search input, move the filtering work into a deferred update with useDeferredValue, virtualize the table so only visible rows render, and memoize chart components that do not depend on the filter. Each change is small, and together they can turn a janky interaction into a smooth one. The exact gains depend on your data and devices, which is why you should verify with before and after measurements.

Step-by-Step Process to Improve INP

  1. Establish a baseline. Pull current INP from CrUX or Search Console and note which page groups fail.
  2. Add field attribution. Install the web-vitals library with attribution and send results to your analytics. Record the target element, event type, and long animation frame details where available.
  3. Reproduce the worst interactions. Use DevTools with 4x or 6x CPU throttling and record the slow interaction. Look for long tasks and the call stack behind them.
  4. Classify the cause. Decide whether the delay comes from input delay (blocked thread), processing (your handler), or presentation (layout and paint).
  5. Apply targeted fixes from the toolbox below, starting with the interaction that affects the most users.
  6. Re-measure in the lab, then ship and watch field data. CrUX updates over a rolling window, so improvements take weeks to be fully reflected.
  7. Prevent regressions. Add INP-aware checks to your pipeline and review new third-party scripts before they ship.

The React Toolbox for Better Responsiveness

Reduce the work per interaction

Avoid doing heavy synchronous work inside event handlers. Move expensive computation out of render and into memoized selectors or web workers. Keep component trees shallow where possible and split giant components so that a state change only re-renders what actually changed. Our guide on React Server Components vs. client components explains how moving non-interactive UI to the server shrinks the JavaScript the browser must run.

Let urgent updates go first

React 18 and later offer concurrent features. startTransition marks non-urgent updates, such as filtering a big list, as interruptible so that typing and clicks stay responsive. useDeferredValue lets an expensive part of the UI lag slightly behind the input. These do not make the work free, but they stop it from blocking the next paint.

Yield to the main thread

Break long tasks into smaller chunks. You can yield with scheduler.yield() where supported, or fall back to setTimeout or requestIdleCallback patterns. The goal is simple: no single task should keep the browser from responding for long stretches.

Virtualize long lists

Rendering thousands of DOM nodes slows layout, paint, and every later interaction. Libraries for windowing render only visible rows. Combine this with pagination or server-side filtering for large datasets.

Control layout and paint cost

Large DOM trees and layout thrashing add presentation delay. Avoid reading layout properties right after writing styles in a loop. Use CSS containment (contain and content-visibility) on off-screen sections so the browser can skip work for them.

Third-Party Scripts: The Silent Offender

Chat widgets, tag managers, A/B testing scripts, and ad tags often run long tasks that block interactions. Audit them regularly.

If your marketing stack is heavy, our guide to server-side tracking for startups shows how to reduce client-side script load while keeping conversion data accurate.

Why INP Matters for Business Outcomes

Core Web Vitals are part of Google's page experience signals, but treat them as one input among many. Relevant content still matters more than a perfect score. The stronger argument for INP is user experience: people abandon forms, carts, and dashboards that feel unresponsive. A responsive interface builds trust, particularly in checkout and sign-up flows where hesitation costs money.

As an illustration, if a checkout page with a laggy "Apply coupon" button causes a fraction of shoppers to give up, even a small improvement in responsiveness could protect revenue. Estimate this with your own funnel data instead of relying on someone else's percentage.

Key Benefits of Improving INP

Common Mistakes to Avoid

Making Performance a Team Habit

One-off fixes decay. Teams that keep good INP treat performance as a feature: they set budgets, review bundle size in pull requests, and monitor field metrics on a dashboard. If you want help auditing a slow product, our web development services include performance reviews, and our SEO services cover the technical side of Core Web Vitals reporting.

Conclusion

INP rewards products that respond quickly to every tap, not just the first one. In React apps, the path to a good score is practical: measure with real user data, find the long tasks behind the slowest interactions, reduce work, and let urgent updates run first. None of this requires a rewrite. It requires patience and a habit of measuring before and after.

Start with your worst page group in Search Console, add attribution, and fix one interaction at a time. Over a few weeks, your users will feel the difference, and your metrics will follow.

Frequently Asked Questions

What is INP?
Interaction to Next Paint measures how quickly a page responds to clicks, taps and key presses across a visit, reporting a value close to the slowest interaction.
What is a good INP score?
According to Google's Web Vitals documentation, 200 milliseconds or less at the 75th percentile is good, and above 500 milliseconds is poor.
Why is my Lighthouse score good but INP poor?
INP is a field metric based on real users and devices. Lab tools cannot fully reproduce it, so check CrUX or the web-vitals library and test with CPU throttling.
Which React features help with INP?
startTransition, useDeferredValue, list virtualization, splitting large components and moving non-interactive UI to the server can all reduce main thread work.
Do third-party scripts affect INP?
Yes. Chat widgets, tag managers and ad scripts often run long tasks. Audit them, defer non-essential ones and remove tags nobody owns.