Skip to main content

Quick start

Import the EmailTheming plugin and add it to your extensions:
import { StarterKit } from '@react-email/editor/extensions';
import { EmailTheming } from '@react-email/editor/plugins';
import { BubbleMenu } from '@react-email/editor/ui';
import { EditorProvider } from '@tiptap/react';
import '@react-email/editor/themes/default.css';

const extensions = [StarterKit, EmailTheming];

export function MyEditor() {
  return (
    <EditorProvider extensions={extensions} content={content}>
      <BubbleMenu.Default />
    </EditorProvider>
  );
}

How theming works

Themes are CSS-in-JS style objects that map to email component types (headings, paragraphs, links, buttons, etc.). Each theme defines a set of React.CSSProperties for every supported component. During composeReactEmail, the EmailTheming plugin acts as a SerializerPlugin that resolves styles for each node based on its type and depth in the document tree. These styles are then inlined directly onto the rendered React Email components as style attributes — this is necessary because email clients don’t reliably support <style> tags or external stylesheets. The resolved styles are passed to each node’s renderToReactEmail() method via the style prop, where they can be spread onto the rendered element.

Built-in themes

The editor ships with two themes:
ThemeDescription
'basic'Full styling — typography, spacing, borders, and visual hierarchy. This is the default.
'minimal'Essentially no styles. Gives you a blank slate to build your own look from scratch.
Select a theme with .configure():
const extensions = [StarterKit, EmailTheming.configure({ theme: 'basic' })];

Switching themes dynamically

Use React state to toggle themes at runtime. Re-key the EditorProvider to apply the new theme:
import { StarterKit } from '@react-email/editor/extensions';
import { EmailTheming } from '@react-email/editor/plugins';
import { BubbleMenu } from '@react-email/editor/ui';
import { EditorProvider } from '@tiptap/react';
import { useState } from 'react';

type EditorTheme = 'basic' | 'minimal';

export function MyEditor() {
  const [theme, setTheme] = useState<EditorTheme>('basic');
  const extensions = [StarterKit, EmailTheming.configure({ theme })];

  return (
    <div>
      <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
        <button onClick={() => setTheme('basic')}>Basic</button>
        <button onClick={() => setTheme('minimal')}>Minimal</button>
      </div>
      <EditorProvider key={theme} extensions={extensions} content={content}>
        <BubbleMenu.Default />
      </EditorProvider>
    </div>
  );
}
The key={theme} on EditorProvider forces React to remount the editor when the theme changes, ensuring the new theme is applied cleanly.

Theme components

Themes define styles for the following email components:
ComponentDescription
resetCSS reset styles
bodyEmail body wrapper
containerContent container
h1Level 1 heading
h2Level 2 heading
h3Level 3 heading
paragraphText paragraphs
listOrdered and unordered lists
listItemIndividual list items
listParagraphParagraphs inside list items
nestedListNested list styles
blockquoteBlock quotes
codeBlockCode blocks
inlineCodeInline code
linkHyperlinks
buttonEmail buttons
sectionContent sections
footerFooter area
hrHorizontal rules
imageImages

Theme-aware serialization

When EmailTheming is in your extensions array, the composeReactEmail function automatically applies theme styles to the exported HTML. No extra configuration needed:
import { composeReactEmail } from '@react-email/editor/core';

// Theme styles are automatically injected into the HTML output
const { html, text } = await composeReactEmail({ editor, preview: null });
See Email Export for more details on the serialization pipeline.