Rendering API
Five render functions:
| Function | Returns | Use Case |
|---|---|---|
renderToHtml | string (combined HTML) | Quick render — saving to disk, ad-hoc HTML |
renderToHtmlParts | { head, body } | Use this when sending email. Splits <style> block from body |
renderToPlainText | string (plain text) | The text/plain MIME part for multipart emails (deliverability) |
renderToJson | DesignJSON | Bootstrap the visual Builder with a code-authored design |
renderRowToJson | DesignRow | Export a single row for the Block Editor |
All are pure synchronous functions: same tree in, same output out, no side effects.
renderToHtml(element, config?)
Takes an Elements tree, returns a clean HTML string. No React hydration markers; ready to ship.
import {
renderToHtml,
Email,
Row,
Column,
ColumnLayouts,
Paragraph,
Button,
} from '@unlayer/react-elements';
const html = renderToHtml(
<Email backgroundColor="#f4f4f4">
<Row layout={ColumnLayouts.OneColumn}>
<Column>
<Paragraph fontSize="14px">Hello World</Paragraph>
<Button backgroundColor="#3b82f6" color="#ffffff">
Click me
</Button>
</Column>
</Row>
</Email>,
);
Signature
function renderToHtml(
element: React.ReactElement,
config?: Partial<UnlayerConfig>,
): string;
The optional config overrides per-render config (cdnBaseUrl, mode, etc.). Throws with a descriptive error if rendering fails.
renderToHtmlParts(element, config?) — recommended for email
Returns head and body separately. The <style> block (hover effects, responsive breakpoints, font declarations) goes in <head>, where Gmail and most webmail clients actually keep style blocks. Dumping the whole document into <body> works for some clients and silently breaks others.
import {
renderToHtmlParts,
Email,
Row,
Column,
Button,
} from '@unlayer/react-elements';
const { head, body } = renderToHtmlParts(
<Email>
<Row>
<Column>
<Button>Click</Button>
</Column>
</Row>
</Email>,
);
const fullHtml = `<!DOCTYPE html>
<html>
<head>${head}</head>
${body}
</html>`;
Signature
function renderToHtmlParts(
element: React.ReactElement,
config?: Partial<UnlayerConfig>,
): HtmlParts;
interface HtmlParts {
head: string; // <style> blocks + optional <script>/<meta>
body: string; // same as renderToHtml output
}
renderToPlainText(element, config?)
Renders to plain text by first rendering to HTML, then stripping markup. Use it for the text/plain MIME part of a multipart email. Including a plain-text alternative meaningfully improves deliverability.
import {
renderToPlainText,
Email,
Row,
Column,
Paragraph,
} from '@unlayer/react-elements';
const text = renderToPlainText(
<Email>
<Row>
<Column>
<Paragraph>Hello World</Paragraph>
</Column>
</Row>
</Email>,
);
// "Hello World"
Signature
function renderToPlainText(
element: React.ReactElement,
config?: Partial<UnlayerConfig>,
): string;
Sending a multipart email
const { head, body } = renderToHtmlParts(<MyEmail />);
const text = renderToPlainText(<MyEmail />);
await mailer.send({
to: 'jane@example.com',
subject: 'Welcome',
html: `<!DOCTYPE html><html><head>${head}</head>${body}</html>`,
text,
});
renderToJson(element)
Renders the component tree to Unlayer-compatible design JSON — the same shape the visual Builders' saveDesign callback produces. The root must be <Body>, <Email>, <Page>, or <Document>.
import {
renderToJson,
Email,
Row,
Column,
ColumnLayouts,
Heading,
} from '@unlayer/react-elements';
const design = renderToJson(
<Email>
<Row layout={ColumnLayouts.OneColumn}>
<Column>
<Heading headingType="h1" fontSize="24px">
Generated from code
</Heading>
</Column>
</Row>
</Email>,
);
// Hand off to the visual builder
emailEditorRef.current.editor.loadDesign(design);
Signature
function renderToJson(element: React.ReactElement): DesignJSON;
Throws if the root element isn't a recognized container component.
When to Use Which
| Goal | Use |
|---|---|
| Send an email (multipart) | renderToHtmlParts + renderToPlainText |
| One-off HTML preview, save to disk | renderToHtml |
| Bootstrap the visual editor with a default design | renderToJson |
| Generate a starter template for a user | renderToJson (then let them edit) |
You can call multiple render functions on the same tree to keep an HTML version for sending and a JSON version for editing.
renderRowToJson(element)
Convert a single <Row> to row JSON. Useful when targeting Unlayer's Block Editor, which works with individual rows rather than full designs.
import {
renderRowToJson,
Row,
Column,
ColumnLayouts,
Paragraph,
} from '@unlayer/react-elements';
const row = renderRowToJson(
<Row layout={ColumnLayouts.OneColumn}>
<Column>
<Paragraph>Block content</Paragraph>
</Column>
</Row>,
);
Signature
function renderRowToJson(element: React.ReactElement): DesignRow;
Throws if the element isn't a <Row>. For full designs, use renderToJson instead.
Server-Side Use
All render functions are pure and run on the server. They work with:
- Plain Node scripts (
node,tsx,bun) - Next.js Route Handlers and Server Actions
- Next.js App Router Server Components
- Remix loaders / actions
- AWS Lambda, Cloudflare Workers (Node-compat), and any other Node-compatible runtime
// app/api/welcome/route.ts (Next.js)
import { NextResponse } from 'next/server';
import { renderToHtmlParts } from '@unlayer/react-elements';
import { WelcomeEmail } from '@/emails/welcome';
export async function GET() {
const { head, body } = renderToHtmlParts(<WelcomeEmail />);
const html = `<!DOCTYPE html><html><head>${head}</head>${body}</html>`;
return new NextResponse(html, { headers: { 'content-type': 'text/html' } });
}
For Server-Component rendering, pass config as a second argument or use <Body config={...}> directly. <UnlayerProvider> requires React Context and isn't available on the server. See Configuration.
See Also
- Output Formats — what each wrapper produces in HTML
- Wrappers — choose the right wrapper before rendering