← Summary · 41 test pages · measured at 31b26561f1

HTML-first examples

These are the 41 server-rendered test pages used to check that the reference implementation (final version df356153a6) neither breaks hydration nor changes what the user sees. Each name opens a live demo with the flag on, and the link beside it shows the page's source. Replace /all/ with /off/ in a demo's address to see the same page with the flag off.

The gzip column is the size of the whole document with the flag on, then the change from the flag-off size. Most pages shrink. A few grow slightly, either because they have little static markup to remove or because the registry row costs more than it saves. Across all 41 pages gzipped bytes fall from 1,023,906 to 586,852 (−42.7%) and inlined Flight from 9,280,754 to 1,977,902 bytes (−78.7%); the median page saves 7.8%.

static

Examplegzip vs stock
attributes-styles-aria
Attribute, style and ARIA variety
Server host elements with many attribute kinds: className, style objects (numeric values, CSS custom properties), data-/aria- attributes, boolean attributes (hidden, inert, open), tabIndex, img srcSet/sizes/loading, link target/rel, table colSpan/rowSpan, and SVG viewBox with camelCase attributes. One client counter.
43040 (-18.7%)
blog-article
Long blog article
Long article with headings, many paragraphs, code blocks, images with alt/width/height and blockquotes, plus one small client like button.
22320 (-17.4%)
dangerous-inner-html
dangerouslySetInnerHTML blocks
Server-rendered dangerouslySetInnerHTML blocks containing rich HTML (nested tags, entities, attributes, inline SVG) mixed with normal JSX siblings. One client counter.
9891 (-50.1%)
docs-sidebar-toc
Docs page with sidebar tree and table of contents
Large server-rendered sidebar navigation tree, an in-page table of contents and content sections, plus one client button that toggles an attribute on itself.
16405 (-58.5%)
form-controls-uncontrolled
Uncontrolled form controls
Server-rendered forms with uncontrolled inputs: defaultValue, defaultChecked, select with optgroup, textarea, radio groups, labels, fieldsets, disabled and readOnly controls. One client counter.
25203 (-4.6%)
fragments-arrays-keys
Fragments, arrays, keys and empty children
Nested and keyed Fragments, keyed arrays, unkeyed text arrays, null/false/undefined/""/0 children, adjacent text nodes, plus one client leaf.
803 (-0.5%)
full-refresh-focus
Typed input value must survive a full refetch
Static server form markup with an uncontrolled input; the user types, the page is refetched (client navigation with full Flight), and the typed value must survive.
668 (+0.3%)
head-hoistables
Head hoistables from deep in the body
Server components deep inside the body render <title>, <meta>, <link rel=preload>, and <style precedence> elements that React hoists into <head>. One client counter.
4819 (-0.5%)
huge-inline-svg
Huge inline SVG
A server-rendered inline <svg> with `size` rects and `size` paths derived from their index, plus one client counter.
57115 (-49.8%)
i18n-text-heavy
Long multilingual text
Many paragraphs of CJK, Arabic (RTL), emoji, accented Latin and characters that must be escaped (& < > "), with HTML entities in literal text.
6347 (-43.2%)
marketing-style-jsonld
Marketing page with inline CSS and JSON-LD
Large inline <style> and JSON-LD <script> emitted by a server component, plus static chrome and one client counter.
35574 (-49.2%)
product-detail-reviews
Product detail with reviews, specs and JSON-LD
Product detail page with a JSON-LD script rendered directly by the server component, a specs table, and a list of size reviews; one client add-to-cart counter.
8527 (-48.3%)
tiny-static
Tiny static page
A few host elements, no client components, no styles.
419 (-18.2%)
whitespace-entities-text
Whitespace and entity text edge cases
Text edge cases in pure server markup: leading/trailing/multiple spaces, newlines in <pre>, adjacent text expressions, empty strings, entities, raw JS-string special characters, emoji/CJK, and long unbroken words. One client counter.
11060 (-50.5%)
wide-tree
Wide flat list
A single <ul> with `size` plain-text siblings, followed by one client counter.
26695 (-79.4%)

composition

Examplegzip vs stock
client-composition-slot
Client component with server-rendered children
A client Panel (toggle state) receives a server-rendered list as children and as a named slot prop.
1236 (-59.0%)
dashboard-client-widgets
Dashboard with client chart widgets
Mostly-server dashboard shell (header, sidebar, stat cards) with many small client widgets rendering inline SVG from numeric props. size = widgets.
3588 (-9.5%)
deep-tree
Deeply nested tree
A chain of `size` nested divs, one paragraph at each level, with a single client counter at the deepest level.
2946 (-6.4%)
islands-many-tiny
Long article with a tiny island after every paragraph
Long static article where each paragraph is followed by a tiny client click-counter island. size = paragraphs.
12560 (-14.6%)
keyed-list-client-reorder
Client list reverses/filters keyed server <li> children
Server passes keyed static <li> elements as children to a client list that can reverse and filter them.
616 (-2.4%)
modal-children-toggle
Client modal with server children, closed by default
A client modal is closed by default (children never rendered during SSR) and opened by click, mounting server-rendered static children.
538 (-4.3%)
realistic-storefront
Realistic storefront with leaf client widgets
Combined storefront page: header and nav, hero carousel, product grid, reviews, footer, inline <style> and JSON-LD, with three small client widgets (cart counter, newsletter form, carousel index) placed as leaves among server markup.
10354 (-15.5%)
server-element-via-props
Server elements passed through several non-children props
A client Layout renders server elements from header/footer/sidebar/slots props immediately (no toggling).
788 (+0.3%)
tabs-panels-prop
Client Tabs with server elements in a panels prop
A client Tabs receives server-rendered static elements in a non-children `panels` array and switches which one is shown.
627 (+1.5%)

client

Examplegzip vs stock
all-client
Everything is a client component
The server root only renders one client component that renders the whole document; nothing to elide.
1010 (+0.6%)
client-only-wrapper
ClientOnly wrapper mounting static server children after an effect
A client ClientOnly renders nothing on the first render and mounts its server-provided static children after an effect.
541 (-3.2%)
nested-layouts-context
Nested client layouts with context
Three nested client layouts each provide a context (theme, locale, user) and render server-passed children; a client leaf reads all three and toggles its theme label.
3133 (-40.9%)
repeated-object-props
Repeated object props
One shared 30-key config object is passed as the same prop to `size` client components, each rendering two of its fields.
2812 (-0.2%)
server-action-form
Form with useActionState and a client-side action
No server-function infrastructure in the fixture: a client form with useActionState and a client-side action, static server markup as children.
849 (-3.2%)
server-error-in-suspense
Client component throws only during SSR inside Suspense
A client component throws only when typeof window is undefined, inside <Suspense> next to static server siblings; React recovers by client-rendering that boundary.
623 (-1.1%)

ecommerce

Examplegzip vs stock
cart-quantity-steppers
Cart with quantity steppers
Ecommerce cart: every line item is server markup with one client quantity stepper as a leaf. size = line items.
5810 (-18.4%)

recursion

Examplegzip vs stock
comments-thread-recursive
Deeply nested recursive comment thread
Pure server comment thread (avatar, author, text, nested replies up to depth 8) laid out as a binary tree; one client collapse-all label button. size = total comments.
9843 (-28.6%)

streaming

Examplegzip vs stock
nested-suspense-waterfall
Three nested async server components with staggered delays
Nested Suspense waterfall (20/30/40 ms), static content at each level, client counter at the leaf.
1247 (+0.6%)
suspense-fallback-shown-late
Suspense fallback shown only after hydration
A client component suspends on user action (use() of a promise created on click, outside a transition) inside a server-rendered <Suspense fallback={static markup}>.
652 (+0.3%)
suspense-many-boundaries
Many independent Suspense boundaries
size async server components, each in its own Suspense boundary, delay 5 + (index * 7) % 60 ms, static content inside.
5149 (-8.0%)
suspense-staggered
Suspense streaming with staggered boundaries
size async server components, each in its own Suspense boundary, resolving after 5ms + 3ms * index.
1981 (-6.4%)

table

Examplegzip vs stock
data-grid-client-cells
20-column data grid, all client cells
Same wide grid, but every cell is a client component receiving its value as a prop (worst case for elision). size = rows.
69570 (-0.1%)
data-grid-server-cells
20-column data grid, all server cells
Wide data grid where every cell is pure server markup; one client selected-row button sits outside the grid. size = rows.
92306 (-59.4%)
product-listing
Server-rendered product grid
Grid of product cards rendered entirely by server components (pure host markup), with one client sort-label button outside the grid.
54730 (-1.9%)
repeated-long-strings
Repeated long strings
A table where every row repeats the same three 232-character strings as text and passes one of them as a prop to a client component.
13196 (+12.4%)
server-table-client-rows
Server-rendered table with a few client rows
size rows rendered by server components; every 10th row (smoke) / 100th (full) holds a client counter.
21261 (-49.7%)