Skip to main content

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:

  • renderDocument accepts the JSON document plus render options. Choose format: 'react' for JSX output, 'html' for static markup, or 'mjml' if you have the MJML renderer installed.
  • The example builds a customBlocks lookup to resolve custom block implementations during rendering. This mirrors the registry passed to the editor.
  • Custom.PreviewProps seeds 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.