# Cumulative layout shift (CLS) in React

> How to fix cumulative layout shift (cls) in React — with the exact fix and copy-paste code.

_Category: Performance · Detector `layout-thrashing` · Severity: warning_

Layout shift is when content jumps after it has already rendered — an image loads and pushes the text down, a banner injects itself above the fold, a web font swaps and reflows everything. It is a Core Web Vitals metric Google ranks on, and it makes users tap the wrong thing. AI-built pages shift constantly because generated markup omits `width`/`height` on images and drops late content in without reserving space.

## The fix for React

Always pass `width` and `height` to `<img>` so the browser can reserve the box before the file loads, even when CSS scales it responsively.

```tsx
<img
  src="/hero.jpg"
  width={1200}
  height={630}
  alt="Hero"
  style={{ width: '100%', height: 'auto' }}
/>
```

### Steps

1. Add `width` and `height` (or `aspect-ratio`) to every image, video, and iframe
2. Reserve a fixed-size slot for anything injected after load (ads, banners, embeds)
3. Use `font-display: optional` or a size-adjusted fallback to avoid font-swap reflow

## How VibeCheck detects it

The `layout-thrashing` detector flags this live in the browser and reports it to the widget's Problems list — and to your coding agent over MCP.

- **Issue string:** `Layout shift cluster detected (3 shifts)`
- **Threshold:** ≥ 3 layout shifts within a 500ms window, with no recent user input

## FAQ

### What CLS score do I need?

Google considers CLS good at 0.1 or below, and poor above 0.25, for 75% of page loads. It is one of the three Core Web Vitals used in ranking.

### Why does the layout-thrashing detector flag this?

VibeCheck observes the browser’s layout-shift entries. When three or more fire within 500ms without user input, it flags a cluster — that burst is exactly what a jumpy load feels like.

### My image is responsive — do I still set `width` and `height`?

Yes. Set the intrinsic `width`/`height` attributes so the browser knows the aspect ratio, then use CSS (`width:100%`; `height:auto`) to scale it. That gives you responsiveness with zero shift.

See the general, framework-agnostic fix: https://vibecheck.wcgw.fun/fix/cumulative-layout-shift.md

---

Fix guide from VibeCheck — https://vibecheck.wcgw.fun/fix/cumulative-layout-shift. Full site index for LLMs: https://vibecheck.wcgw.fun/llms.txt
