Web Performance & SEO

Core Web Vitals Engineering Playbook: Fixing LCP, INP, and CLS in React & Vite SPAs

Actionable engineering fixes to get Largest Contentful Paint (LCP) under 2.5s, Interaction to Next Paint (INP) under 200ms, and Cumulative Layout Shift (CLS) under 0.1.

By Cometflow Web Performance Team • Updated 2026-11-02

Google Search uses Core Web Vitals field data (CrUX) as a page experience ranking signal. Passing the assessment requires hitting the 75th percentile threshold across three metrics: Largest Contentful Paint (LCP ≤ 2.5s), Interaction to Next Paint (INP ≤ 200ms), and Cumulative Layout Shift (CLS ≤ 0.10).

1. Optimizing LCP: Hero Image Byte Weight & Fetch Priority

In over 70% of web pages, the Largest Contentful Paint element is a hero banner image or product photograph. Convert hero PNG/JPG images to WebP using the PNG to WebP Converter and never apply loading="lazy" to above-the-fold images:

<!-- Above-the-fold Hero Image: Eager load + High fetch priority + Explicit dimensions -->
<img
  src="/assets/hero-workspace.webp"
  width="1200"
  height="630"
  fetchpriority="high"
  decoding="async"
  alt="Workspace preview"
/>

2. Eliminating CLS & Reducing INP Main-Thread Blocking

  • Reserve Explicit Aspect Ratio Boxes (CLS < 0.1): Always specify width and height attributes on images, embeds, and ad containers so the browser reserves layout space before network payloads arrive.
  • Yield to the Main Thread on Heavy Input (INP < 200ms): Break long synchronous filter or search calculations into micro-tasks using React.startTransition or requestAnimationFrame so the browser can paint visual feedback immediately after a user keystroke.

Frequently Asked Questions

What replaced First Input Delay (FID) in Google Core Web Vitals?

Interaction to Next Paint (INP) officially replaced FID as a Core Web Vital. Unlike FID, which only measured the input delay of the very first click, INP measures the full latency (input delay + event handler execution + next frame paint) across all user interactions during a page visit.

Why do hero images hurt LCP in React single-page applications?

In a client-rendered SPA, the browser cannot discover an <img> tag inside a lazy-loaded React component until the JavaScript bundle downloads, parses, and executes. Preloading the hero WebP image in index.html and setting fetchpriority="high" fixes this.