Files

220 lines
6.6 KiB
Plaintext

---
title: "Email Theming"
sidebarTitle: "Theming"
description: "Apply and customize visual themes for email output."
icon: "palette"
---
## Quick start
Import the `EmailTheming` plugin and add it to your extensions:
```tsx
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 />
</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`](/editor/api-reference/compose-react-email), 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:
| Theme | Description |
|-------|-------------|
| `'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()`:
```tsx
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:
```tsx
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 />
</EditorProvider>
</div>
);
}
```
<Info>
The `key={theme}` on `EditorProvider` forces React to remount the editor when the theme changes,
ensuring the new theme is applied cleanly.
</Info>
## Custom themes
Instead of being limited to built-in presets, you can define custom themes using a CSS-in-JS
object that maps component names to styles.
### Extending a built-in theme
Use `extendTheme` to start from a built-in theme and override specific styles:
```tsx
import { StarterKit } from '@react-email/editor/extensions';
import { EmailTheming, extendTheme } from '@react-email/editor/plugins';
import { EditorProvider } from '@tiptap/react';
const brandTheme = extendTheme('basic', {
body: { backgroundColor: '#eff6ff' },
h1: { color: '#1e40af', fontSize: '28px' },
button: { backgroundColor: '#2563eb', color: '#fff', borderRadius: '6px' },
link: { color: '#2563eb' },
});
const extensions = [StarterKit, EmailTheming.configure({ theme: brandTheme })];
export function MyEditor() {
return (
<EditorProvider extensions={extensions} content={content}>
{/* ... */}
</EditorProvider>
);
}
```
### Creating a theme from scratch
Use `createTheme` to build a theme without inheriting from a built-in preset.
When no `extends` is set, the `minimal` reset is used as a base:
```tsx
import { createTheme } from '@react-email/editor/plugins';
const darkTheme = createTheme({
body: { backgroundColor: '#1a1a2e', color: '#e2e8f0' },
container: { backgroundColor: '#16213e', color: '#e2e8f0' },
h1: { color: '#e2e8f0' },
link: { color: '#60a5fa' },
button: { backgroundColor: '#3b82f6', color: '#fff', borderRadius: '4px' },
});
```
### Passing a theme config inline
You can also pass a `ThemeConfig` object directly to the `theme` prop without using the
helper functions:
```tsx
<EmailEditor
theme={{
extends: 'basic',
styles: {
body: { backgroundColor: '#f4f4f5' },
button: { backgroundColor: '#0670DB' },
},
}}
/>
```
<Info>
Custom theme values appear in the inspector UI, and users can still tweak them
interactively. The inspector doesn't distinguish between built-in and custom values.
</Info>
## Theme components
Themes define styles for the following email components:
| Component | Description |
|-----------|-------------|
| `reset` | CSS reset styles |
| `body` | Email body wrapper |
| `container` | Content container |
| `h1` | Level 1 heading |
| `h2` | Level 2 heading |
| `h3` | Level 3 heading |
| `paragraph` | Text paragraphs |
| `list` | Ordered and unordered lists |
| `listItem` | Individual list items |
| `listParagraph` | Paragraphs inside list items |
| `nestedList` | Nested list styles |
| `blockquote` | Block quotes |
| `codeBlock` | Code blocks |
| `inlineCode` | Inline code |
| `link` | Hyperlinks |
| `button` | Email buttons |
| `section` | Content sections |
| `footer` | Footer area |
| `hr` | Horizontal rules |
| `image` | Images |
## Theme-aware serialization
When `EmailTheming` is in your extensions array, the `composeReactEmail` function automatically
applies theme styles to the exported HTML. No extra configuration is needed.
```tsx
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](/editor/features/email-export) for more details on the serialization pipeline.
## Examples
See theming in action with a runnable example:
<CardGroup cols={2}>
<Card title="Email Theming" icon="code" href="https://react.email/editor/examples/email-theming">
Basic/Minimal/Custom theme toggle with live preview.
</Card>
<Card title="Custom Themes" icon="palette" href="https://react.email/editor/examples/custom-theme">
Define custom themes with createTheme and extendTheme.
</Card>
</CardGroup>