Files
react/packages/react-markup
Sebastian Markbåge d177272802 [Fizz] Error and deopt from rel=expect for large documents without boundaries (#33454)
We want to make sure that we can block the reveal of a well designed
complete shell reliably. In the Suspense model, client transitions don't
have any way to implicitly resolve. This means you need to use Suspense
or SuspenseList to explicitly split the document. Relying on implicit
would mean you can't add a Suspense boundary later where needed. So we
highly encourage the use of them around large content.

However, if you have constructed a too large shell (e.g. by not adding
any Suspense boundaries at all) then that might take too long to render
on the client. We shouldn't punish users (or overzealous metrics
tracking tools like search engines) in that scenario.

This opts out of render blocking if the shell ends up too large to be
intentional and too slow to load. Instead it deopts to showing the
content split up in arbitrary ways (browser default). It only does this
for SSR, and not client navs so it's not reliable.

In fact, we issue an error to `onError`. This error is recoverable in
that the document is still produced. It's up to your framework to decide
if this errors the build or just surface it for action later.

What should be the limit though? There's a trade off here. If this limit
is too low then you can't fit a reasonably well built UI within it
without getting errors. If it's too high then things that accidentally
fall below it might take too long to load.

I came up with 512kB of uncompressed shell HTML. See the comment in code
for the rationale for this number. TL;DR: Data and theory indicates that
having this much content inside `rel="expect"` doesn't meaningfully
change metrics. Research of above-the-fold content on various websites
indicate that this can comfortable fit all of them which should be
enough for any intentional initial paint.
2025-06-06 10:29:48 -04:00
..

react-markup

This package provides the ability to render standalone HTML from Server Components for use in embedded contexts such as e-mails and RSS/Atom feeds. It cannot use Client Components and does not hydrate. It is intended to be paired with the generic React package, which is shipped as react to npm.

Installation

npm install react react-markup

Usage

import { experimental_renderToHTML as renderToHTML } from 'react-markup';
import EmailTemplate from './my-email-template-component.js'

async function action(email, name) {
  "use server";
  // ... in your server, e.g. a Server Action...
  const htmlString = await renderToHTML(<EmailTemplate name={name} />);
  // ... send e-mail using some e-mail provider
  await sendEmail({ to: email, contentType: 'text/html', body: htmlString });
}

Note that this is an async function that needs to be awaited - unlike the legacy renderToString in react-dom.

API

react-markup

See https://react.dev/reference/react-markup

Thanks

The React team thanks Nikolai Mavrenkov for donating the react-markup package name.