Rendering Examples
The renderer example app (packages/renderer/example) demonstrates how to turn editor JSON into React output (or MJML/HTML, depending on the format you request). A representative entry renders a document that mixes built-in components with the same custom hero block used in the editor example.
packages/renderer/example/emails/custom-w-comp.tsx
import { renderDocument } from '@react-email-dnd/renderer';
import { type CanvasDocument } from '@react-email-dnd/shared';
import { customBlocks } from './components/custom-blocks';
import themes from '../themes.json';
import email from '../../emails/plain-w-components.json';
const template: CanvasDocument = email as CanvasDocument;
export default function Custom({ document }: { document: CanvasDocument }) {
const theme = themes.forest;
const customBlocksRegistry = customBlocks.reduce((acc, definition) => {
acc[definition.defaults.componentName] = definition;
return acc;
}, {} as Record<string, (typeof customBlocks)[number]>);
const result = renderDocument({
document,
options: {
format: 'react',
theme,
customBlocks: customBlocksRegistry,
},
});
return result.format === 'react' ? result.node : null;
}
Custom.PreviewProps = {
document: template,
};
Highlights:
renderDocumentaccepts the JSON document plus renderoptions. Chooseformat: 'react'for JSX output,'html'for static markup, or'mjml'if you have the MJML renderer installed.- The example builds a
customBlockslookup to resolve custom block implementations during rendering. This mirrors the registry passed to the editor. Custom.PreviewPropsseeds the playground UI so you can render the example immediately without manually pasting JSON.
Custom block implementation
The renderer reuses the same HeroBlock definition as the editor, including default props and controlled form logic:
packages/renderer/example/emails/components/custom-blocks.tsx
export const heroBlockDefinition: CustomBlockDefinition<HeroBlockProps> = {
id: 'hero-banner',
type: 'custom',
label: 'Hero Banner',
icon: SparkleIcon,
defaults: {
componentName: 'HeroBlock',
props: {
title: 'Launch something delightful',
description:
'Announce a promotion, product update, or new feature with a bold hero.',
ctaLabel: 'Shop now',
ctaHref: 'https://example.com',
backgroundColor: '#0ea5e9',
textColor: '#ffffff',
},
},
component: HeroBlock,
propEditor: HeroBlockPropsEditor,
};
Because the renderer relies on the same defaults and IDs, authors editing the block in the editor see identical output once the campaign is rendered.
Running the renderer playground
cd packages/renderer/example
pnpm install
pnpm dev
The dev server shows a gallery of email templates—including the custom block example above—so you can verify typography, layouts, and theme tokens before sending.