> ## Documentation Index
> Fetch the complete documentation index at: https://react.email/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Email Theming

> Apply and customize visual themes for email output.

## Quick start

Import the `EmailTheming` plugin and add it to your extensions:

```tsx theme={"theme":{"light":"github-light","dark":"vesper"}}
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 theme={"theme":{"light":"github-light","dark":"vesper"}}
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 theme={"theme":{"light":"github-light","dark":"vesper"}}
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 theme={"theme":{"light":"github-light","dark":"vesper"}}
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 theme={"theme":{"light":"github-light","dark":"vesper"}}
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 theme={"theme":{"light":"github-light","dark":"vesper"}}
<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 theme={"theme":{"light":"github-light","dark":"vesper"}}
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>
