From 99a95f100e09dc3ebd5ffdedbbbfb3e9b10d4672 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 18 Nov 2025 15:52:44 +0100 Subject: [PATCH 1/3] fix: allow configuring the email body's styles --- docs/content/docs/features/export/email.mdx | 7 +++++++ .../reactEmailExporter.test.tsx.snap | 2 ++ .../src/react-email/reactEmailExporter.test.tsx | 15 +++++++++++++++ .../src/react-email/reactEmailExporter.tsx | 11 +++++++++++ 4 files changed, 35 insertions(+) diff --git a/docs/content/docs/features/export/email.mdx b/docs/content/docs/features/export/email.mdx index 7422c7ac80..ec48caa4bc 100644 --- a/docs/content/docs/features/export/email.mdx +++ b/docs/content/docs/features/export/email.mdx @@ -56,6 +56,7 @@ See the [full example](/examples/interoperability/converting-blocks-to-react-ema - **footer**: Add content to the bottom of the email (must be a React-Email compatible component) - **head**: Inject elements into the [Head element](https://react.email/docs/components/head) - **container**: Customize the container element (A component which will wrap the email content including the header and footer) +- **bodyStyles**: Customize the body styles (a `CSSProperties` object) Example usage: @@ -82,6 +83,12 @@ const html = await exporter.toReactEmailDocument(editor.document, { footer: Footer, head: My email, container: ({ children }) => {children}, + bodyStyles: { + fontFamily: "Arial, sans-serif", + fontSize: "14px", + lineHeight: "1.5", + color: "#333", + }, }); ``` diff --git a/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap b/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap index cfc448f101..3c54a44c07 100644 --- a/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap +++ b/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap @@ -14,6 +14,8 @@ exports[`react email exporter > should handle document with code blocks > __snap exports[`react email exporter > should handle document with complex nested structure > __snapshots__/reactEmailExporterComplexNested 1`] = `"

Complex Document

This is a paragraph with bold and italic text, plus a link.

"`; +exports[`react email exporter > should handle document with custom body styles > __snapshots__/reactEmailExporterCustomBodyStyles 1`] = `"

Welcome to this demo 🙌!

Hello World nested

Hello World double nested

This paragraph has a background color

Paragraph

Heading

Heading right

justified paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.


  1. Numbered List Item

Check List Item

Wide CellTable CellTable Cell
Wide CellTable CellTable Cell
Wide CellTable CellTable Cell
From https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg
Open video file

From https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm

Open audio file

From https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3

audio.mp3

Audio file caption

Inline Content:

Styled Text Link

Table Cell 1Table Cell 2Table Cell 3
Table Cell 4Table Cell Bold 5Table Cell 6
Table Cell 7Table Cell 8Table Cell 9

const helloWorld = (message) => {

console.log("Hello World", message);

};


"`; + exports[`react email exporter > should handle document with headings of different levels > __snapshots__/reactEmailExporterHeadings 1`] = `"

Heading 1

Heading 2

Heading 3

"`; exports[`react email exporter > should handle document with links > __snapshots__/reactEmailExporterWithLinks 1`] = `"

Click here

"`; diff --git a/packages/xl-email-exporter/src/react-email/reactEmailExporter.test.tsx b/packages/xl-email-exporter/src/react-email/reactEmailExporter.test.tsx index 6075852536..7688f2e833 100644 --- a/packages/xl-email-exporter/src/react-email/reactEmailExporter.test.tsx +++ b/packages/xl-email-exporter/src/react-email/reactEmailExporter.test.tsx @@ -783,4 +783,19 @@ describe("react email exporter", () => { expect(html).toMatchSnapshot("__snapshots__/reactEmailExporterMixedLists"); }); + + it("should handle document with custom body styles", async () => { + const exporter = new ReactEmailExporter( + BlockNoteSchema.create(), + reactEmailDefaultSchemaMappings, + ); + + const html = await exporter.toReactEmailDocument(testDocument as any, { + bodyStyles: { fontFamily: "Arial, sans-serif" }, + }); + + expect(html).toMatchSnapshot( + "__snapshots__/reactEmailExporterCustomBodyStyles", + ); + }); }); diff --git a/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx b/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx index 191ae980ad..af053daa7f 100644 --- a/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx +++ b/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx @@ -292,6 +292,16 @@ export class ReactEmailExporter< * Customize the container element */ container?: React.FC<{ children: React.ReactNode }>; + /** + * Customize the body styles + * @default { + * fontFamily: "'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif", + * fontSize: "16px", + * lineHeight: "1.5", + * color: "#333", + * } + */ + bodyStyles?: CSSProperties; }, ) { const transformedBlocks = await this.transformBlocks(blocks); @@ -310,6 +320,7 @@ export class ReactEmailExporter< fontSize: "16px", lineHeight: "1.5", color: "#333", + ...options?.bodyStyles, }} > {options?.preview && {options.preview}} From ea3ef9b1e210c38f158b7524d599c95b5f7620a0 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 18 Nov 2025 15:57:34 +0100 Subject: [PATCH 2/3] fix: replace the whole object, don't just merge it with our defaults --- .../reactEmailExporter.test.tsx.snap | 2 +- .../src/react-email/reactEmailExporter.tsx | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap b/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap index 3c54a44c07..0766ced3fe 100644 --- a/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap +++ b/packages/xl-email-exporter/src/react-email/__snapshots__/reactEmailExporter.test.tsx.snap @@ -14,7 +14,7 @@ exports[`react email exporter > should handle document with code blocks > __snap exports[`react email exporter > should handle document with complex nested structure > __snapshots__/reactEmailExporterComplexNested 1`] = `"

Complex Document

This is a paragraph with bold and italic text, plus a link.

"`; -exports[`react email exporter > should handle document with custom body styles > __snapshots__/reactEmailExporterCustomBodyStyles 1`] = `"

Welcome to this demo 🙌!

Hello World nested

Hello World double nested

This paragraph has a background color

Paragraph

Heading

Heading right

justified paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.


  1. Numbered List Item

Check List Item

Wide CellTable CellTable Cell
Wide CellTable CellTable Cell
Wide CellTable CellTable Cell
From https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg
Open video file

From https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm

Open audio file

From https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3

audio.mp3

Audio file caption

Inline Content:

Styled Text Link

Table Cell 1Table Cell 2Table Cell 3
Table Cell 4Table Cell Bold 5Table Cell 6
Table Cell 7Table Cell 8Table Cell 9

const helloWorld = (message) => {

console.log("Hello World", message);

};


"`; +exports[`react email exporter > should handle document with custom body styles > __snapshots__/reactEmailExporterCustomBodyStyles 1`] = `"

Welcome to this demo 🙌!

Hello World nested

Hello World double nested

This paragraph has a background color

Paragraph

Heading

Heading right

justified paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.


  1. Numbered List Item

Check List Item

Wide CellTable CellTable Cell
Wide CellTable CellTable Cell
Wide CellTable CellTable Cell
From https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg
Open video file

From https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm

Open audio file

From https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3

audio.mp3

Audio file caption

Inline Content:

Styled Text Link

Table Cell 1Table Cell 2Table Cell 3
Table Cell 4Table Cell Bold 5Table Cell 6
Table Cell 7Table Cell 8Table Cell 9

const helloWorld = (message) => {

console.log("Hello World", message);

};


"`; exports[`react email exporter > should handle document with headings of different levels > __snapshots__/reactEmailExporterHeadings 1`] = `"

Heading 1

Heading 2

Heading 3

"`; diff --git a/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx b/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx index af053daa7f..5c9c8a2fe6 100644 --- a/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx +++ b/packages/xl-email-exporter/src/react-email/reactEmailExporter.tsx @@ -314,14 +314,15 @@ export class ReactEmailExporter< {options?.head} {options?.preview && {options.preview}} From 02d6c5be236b4126dd7f1757e2b2a00fcd4216d5 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 18 Nov 2025 17:09:11 +0100 Subject: [PATCH 3/3] docs: clarify default values --- docs/content/docs/features/export/email.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/content/docs/features/export/email.mdx b/docs/content/docs/features/export/email.mdx index ec48caa4bc..a6599b7694 100644 --- a/docs/content/docs/features/export/email.mdx +++ b/docs/content/docs/features/export/email.mdx @@ -56,7 +56,7 @@ See the [full example](/examples/interoperability/converting-blocks-to-react-ema - **footer**: Add content to the bottom of the email (must be a React-Email compatible component) - **head**: Inject elements into the [Head element](https://react.email/docs/components/head) - **container**: Customize the container element (A component which will wrap the email content including the header and footer) -- **bodyStyles**: Customize the body styles (a `CSSProperties` object) +- **bodyStyles**: Customize the body styles (a `CSSProperties` object), providing an object here will completely override the default styles with what you provide Example usage: @@ -83,9 +83,11 @@ const html = await exporter.toReactEmailDocument(editor.document, { footer: Footer, head: My email, container: ({ children }) => {children}, + // These are the default body styles that are set by default bodyStyles: { - fontFamily: "Arial, sans-serif", - fontSize: "14px", + fontFamily: + "'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif", + fontSize: "16px", lineHeight: "1.5", color: "#333", },