Wrappers
There are four root wrappers. Three are semantic shortcuts; the fourth is the underlying primitive.
| Wrapper | Output Style | Target | When to use |
|---|---|---|---|
<Email> | Table-based HTML | Email clients | Sending emails |
<Page> | div + flexbox HTML | Responsive web | Landing pages, web previews |
<Document> | Print-tuned HTML | PDF generation | Invoices, reports |
<Body> | Whatever mode says | Advanced | Set mode dynamically, or thread an SSR config prop explicitly |
Email, Page, and Document are thin wrappers around Body that lock the mode prop. Roughly:
function Email(props) {
return <Body {...props} mode="email" />;
}
function Page(props) {
return <Body {...props} mode="web" />;
}
function Document(props) {
return <Body {...props} mode="document" />;
}
All three accept the same props as Body (minus mode).
<Email>
For content that will go through an email service provider and render inside an email client. The output is tables, inline styles, and the rest of the bag of tricks that survives Outlook and Gmail.
Props (selected)
EmailProps = Omit<BodyProps, "mode">. The most commonly used:
| Prop | Type | Default |
|---|---|---|
backgroundColor | string | "#F7F8F9" |
contentWidth | string | "500px" |
contentAlign | "center" | "left" | "right" | "center" |
contentVerticalAlign | "top" | "middle" | "bottom" | "middle" |
fontFamily | { label: string, value: string } | { label: "Arial", value: "arial,helvetica,sans-serif" } |
textColor | string | "#000000" |
linkStyle | LinkStyle | { body: true, linkColor: "#0000ee", linkHoverColor: "#0000ee", linkUnderline: true, linkHoverUnderline: true } |
backgroundImage | { url, fullWidth, repeat, size, position } | empty image |
previewText | string | — |
config | Partial<UnlayerConfig> | (SSR escape hatch) |
previewText is the preheader most inboxes show next to the subject. It renders as hidden HTML padded to ~150 characters with invisible Unicode so the inbox preview doesn't bleed into the next visible content.
LinkStyle shape
interface LinkStyle {
body?: boolean; // true on the wrapper — applies styles to body links
inherit?: boolean; // true on a content component — inherit body link style
linkColor?: string;
linkHoverColor?: string;
linkUnderline?: boolean;
linkHoverUnderline?: boolean;
}
The wrapper uses body: true to mark its values as the document-level link style. Content components (Heading, Paragraph, Table, etc.) accept the same shape but use inherit: true to opt into the body-level style instead of defining their own.
backgroundImage shape
interface BackgroundImage {
url: string;
fullWidth?: boolean;
repeat?: 'no-repeat' | 'repeat' | 'repeat-x' | 'repeat-y';
size?: 'cover' | 'contain' | 'custom';
position?: 'center' | 'top' | 'bottom' | 'left' | 'right' | string;
}
Set url: "" (the default) for no background image.
Example
import {
Email,
Row,
Column,
ColumnLayouts,
Paragraph,
renderToHtml,
} from '@unlayer/react-elements';
const html = renderToHtml(
<Email
backgroundColor="#f4f4f4"
contentWidth="600px"
previewText="Your weekly digest is here"
>
<Row layout={ColumnLayouts.OneColumn}>
<Column padding="20px">
<Paragraph fontSize="16px">Hello from Unlayer!</Paragraph>
</Column>
</Row>
</Email>,
);
<Page>
For responsive landing pages, web previews, or any HTML you'll render in a browser viewport. Uses div + flexbox instead of tables.
Props
PageProps = Omit<BodyProps, "mode">. Same shape as <Email>. previewText is meaningful only in email mode and is ignored here.
Example
import {
Page,
Row,
Column,
ColumnLayouts,
Heading,
Paragraph,
renderToHtml,
} from '@unlayer/react-elements';
const html = renderToHtml(
<Page contentWidth="1200px" backgroundColor="#ffffff">
<Row layout={ColumnLayouts.TwoEqual} padding="40px">
<Column>
<Heading headingType="h1" fontSize="32px">
Build with Unlayer
</Heading>
</Column>
<Column>
<Paragraph fontSize="16px">
Render the same components to email, web, and PDF.
</Paragraph>
</Column>
</Row>
</Page>,
);
<Document>
For print-targeted output: invoices, certificates, reports, contracts. Pair the HTML output with a headless browser or PDF library on your server to produce the final PDF.
Props
DocumentProps = Omit<BodyProps, "mode">. Same shape as <Email> and <Page>.
Example
import {
Document,
Row,
Column,
ColumnLayouts,
Heading,
Paragraph,
renderToHtml,
} from '@unlayer/react-elements';
const html = renderToHtml(
<Document contentWidth="8.5in">
<Row layout={ColumnLayouts.OneColumn} padding="40px">
<Column>
<Heading headingType="h1" fontSize="28px">
Invoice #1042
</Heading>
<Paragraph fontSize="14px">Issued on 2026-05-05</Paragraph>
</Column>
</Row>
</Document>,
);
// hand the html string to puppeteer / playwright / wkhtmltopdf etc.
<Body> (Advanced)
<Body> is the primitive the others wrap. Use it directly when you need to:
- Set
modedynamically (e.g., from a runtime flag). - Pass an SSR
configprop instead of relying on<UnlayerProvider>Context.
Props
| Prop | Type | Notes |
|---|---|---|
mode | "web" | "email" | "document" | Default: "web" (or whatever config.mode says) |
config | Partial<UnlayerConfig> | For Server Components where Context isn't available |
previewText | string | Email-mode preview text |
children | React.ReactNode | Must be <Row> elements |
| ...semantic props | (same as Email/Page/Document) | backgroundColor, contentWidth, etc. |
Example: SSR with explicit config
import {
Body,
Row,
Column,
Paragraph,
renderToHtml,
} from '@unlayer/react-elements';
const html = renderToHtml(
<Body
mode="email"
config={{ cdnBaseUrl: 'https://cdn.example.com' }}
backgroundColor="#ffffff"
previewText="Preview from a Server Component"
>
<Row>
<Column>
<Paragraph>Hello from a Server Component</Paragraph>
</Column>
</Row>
</Body>,
);
For a fixed render mode, the semantic wrappers (<Email>, <Page>, <Document>) read better.
Choosing a Wrapper
The wrapper is decided by where the HTML will be viewed, not by what it contains. A "newsletter" rendered for the web is a <Page>; the same content mailed out is an <Email>.
You can render the same content tree under different wrappers in the same codebase, which is useful when you need both an email and a web archive of the same campaign.
See Also
- Components — Layout —
Row,Column,ColumnLayouts - Output Formats — what each wrapper produces in detail
- Configuration — global settings via
UnlayerProviderand theconfigprop