Setting ssr: false on above-the-fold components — the header, hero, and navigation — means the server sends empty HTML for those regions, and users see a blank viewport until JavaScript hydrates. This damages First Contentful Paint (FCP) and the perceived speed of the page, even when the full page eventually loads quickly. Browser pre-rendering and crawler indexing also fail for these regions: search engine snapshots taken before hydration miss the content entirely. ISO 25010 performance-efficiency.time-behaviour defines time-behaviour as the time from user action to visible response — a blank viewport is a failure of that response.
Low because hydration blocking typically causes a brief flash of blank content rather than a total failure, but on slow connections it extends to several seconds of blank above-the-fold space.
Remove ssr: false from above-the-fold components. Server-render the static structure of the header and hero, then hydrate interactive elements after paint. Reserve ssr: false for components that genuinely cannot run on the server (browser-only APIs, WebGL, certain chart libraries).
// Before — header blank until JS hydrates
const Header = dynamic(() => import('./Header'), { ssr: false })
// After — server renders static header structure immediately
import Header from './Header' // static import, SSR-compatible
// Interactive elements inside Header hydrate after paint
// Pattern: server-render shell, hydrate interactive parts lazily
// app/layout.tsx
export default function Layout({ children }) {
return (
<>
<Header /> {/* server-rendered static markup */}
<main>{children}</main>
<DynamicChatWidget /> {/* ssr: false acceptable — below fold, not critical */}
</>
)
}
const DynamicChatWidget = dynamic(() => import('./ChatWidget'), {
ssr: false,
loading: () => null
})
ID: performance-load.rendering.hydration-strategy
Severity: low
What to look for: Count all components rendered above the fold (header, hero, navigation) on the primary landing pages. For each above-the-fold component, check whether it uses ssr: false, dynamic(() => ..., { ssr: false }), or requires full JavaScript hydration before any content is visible. Classify each as: (a) renders static HTML first, hydrates after paint, or (b) requires JS before any content appears (blank until hydration). Enumerate: "X above-the-fold components found, Y render without requiring JS hydration."
Pass criteria: At least 90% of above-the-fold components render static HTML before hydration. No more than 1 above-the-fold component uses ssr: false. Static HTML is served first on all primary landing pages; hydration happens after content is painted. Report: "X of Y above-the-fold components render server HTML before hydration."
Fail criteria: 2 or more above-the-fold components require full JavaScript hydration before any content is visible, or any primary landing page is blank until JavaScript loads.
Skip (N/A) when: Framework does not use hydration (pure server-rendered without client JS, or pure CSR where this check is covered by no-client-only-seo).
Detail on fail: "3 of 5 above-the-fold components use ssr: false — header, hero, and nav are blank until JS loads" or "Dashboard layout uses ssr: false for sidebar and chart — 2 above-fold components block rendering"
Remediation: Use lazy hydration or defer non-critical interactivity:
// Before — blocks hydration
export default function Dashboard() {
return (
<>
<Header /> {/* Heavy interactive component */}
<Content />
</>
)
}
// After — static content first, interactivity deferred
export default function Dashboard() {
return (
<>
<StaticHeader /> {/* Just static markup */}
<Content />
<DynamicHeader client:load /> {/* Hydrate dynamically */}
</>
)
}
// Or lazy hydrate non-critical components
const LazyInteractiveWidget = dynamic(() => import('./Widget'), {
loading: () => <Skeleton />,
ssr: false
})