mirror of
https://github.com/resend/react-email.git
synced 2026-09-14 14:18:02 +08:00
220 lines
6.6 KiB
Plaintext
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>
|