mirror of
https://github.com/resend/react-email.git
synced 2026-09-14 14:18:02 +08:00
320 lines
6.5 KiB
Plaintext
320 lines
6.5 KiB
Plaintext
---
|
|
title: "Theming API"
|
|
sidebarTitle: "Theming API"
|
|
description: "Types and utilities for the email theming system."
|
|
icon: "swatchbook"
|
|
---
|
|
|
|
## EmailTheming extension
|
|
|
|
The `EmailTheming` extension from `@react-email/editor/plugins` adds theme-aware styling
|
|
to the editor and provides a `SerializerPlugin` for theme-aware HTML export.
|
|
|
|
```tsx
|
|
import { EmailTheming } from '@react-email/editor/plugins';
|
|
|
|
const extensions = [StarterKit, EmailTheming.configure({ theme: 'basic' })];
|
|
```
|
|
|
|
<ResponseField name="theme" type="EditorThemeInput" default="'basic'">
|
|
The active theme. Accepts a built-in preset (`'basic'` or `'minimal'`) or a `ThemeConfig`
|
|
object for custom themes.
|
|
</ResponseField>
|
|
|
|
## Types
|
|
|
|
### EditorTheme
|
|
|
|
```tsx
|
|
type EditorTheme = 'basic' | 'minimal';
|
|
```
|
|
|
|
---
|
|
|
|
### EditorThemeInput
|
|
|
|
The widened theme type accepted by the `theme` prop and `EmailTheming.configure()`:
|
|
|
|
```tsx
|
|
type EditorThemeInput = EditorTheme | ThemeConfig;
|
|
```
|
|
|
|
---
|
|
|
|
### ThemeableComponent
|
|
|
|
The subset of `KnownThemeComponents` that can be customized via `ThemeComponentStyles`:
|
|
|
|
```tsx
|
|
type ThemeableComponent =
|
|
| 'body'
|
|
| 'container'
|
|
| 'h1'
|
|
| 'h2'
|
|
| 'h3'
|
|
| 'link'
|
|
| 'image'
|
|
| 'button'
|
|
| 'codeBlock'
|
|
| 'inlineCode';
|
|
```
|
|
|
|
---
|
|
|
|
### ThemeComponentStyles
|
|
|
|
CSS-in-JS styles keyed by themeable component name:
|
|
|
|
```tsx
|
|
type ThemeComponentStyles = {
|
|
[K in ThemeableComponent]?: React.CSSProperties & {
|
|
align?: 'center' | 'left' | 'right';
|
|
};
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### ThemeConfig
|
|
|
|
A custom theme configuration object:
|
|
|
|
```tsx
|
|
interface ThemeConfig {
|
|
extends?: EditorTheme;
|
|
styles: ThemeComponentStyles;
|
|
}
|
|
```
|
|
|
|
<ResponseField name="extends" type="EditorTheme">
|
|
The built-in theme to inherit from. If omitted, uses `'minimal'` reset styles as a base.
|
|
</ResponseField>
|
|
|
|
<ResponseField name="styles" type="ThemeComponentStyles" required>
|
|
CSS-in-JS styles keyed by component name. Values are merged on top of the base theme.
|
|
</ResponseField>
|
|
|
|
---
|
|
|
|
### KnownThemeComponents
|
|
|
|
All component keys that a theme can style:
|
|
|
|
```tsx
|
|
type KnownThemeComponents =
|
|
| 'reset'
|
|
| 'body'
|
|
| 'container'
|
|
| 'h1'
|
|
| 'h2'
|
|
| 'h3'
|
|
| 'paragraph'
|
|
| 'list'
|
|
| 'listItem'
|
|
| 'listParagraph'
|
|
| 'nestedList'
|
|
| 'blockquote'
|
|
| 'codeBlock'
|
|
| 'inlineCode'
|
|
| 'link'
|
|
| 'button'
|
|
| 'section'
|
|
| 'footer'
|
|
| 'hr'
|
|
| 'image';
|
|
```
|
|
|
|
---
|
|
|
|
### KnownCssProperties
|
|
|
|
CSS properties that can be customized per theme component:
|
|
|
|
**Layout:** `align`, `width`, `height`, `padding`, `paddingTop`, `paddingRight`,
|
|
`paddingBottom`, `paddingLeft`, `margin`, `marginTop`, `marginRight`, `marginBottom`,
|
|
`marginLeft`
|
|
|
|
**Appearance:** `backgroundColor`, `color`, `borderRadius`, `borderWidth`, `borderColor`,
|
|
`borderStyle`
|
|
|
|
**Typography:** `fontSize`, `fontWeight`, `lineHeight`, `textDecoration`, `fontFamily`,
|
|
`letterSpacing`
|
|
|
|
---
|
|
|
|
### CssJs
|
|
|
|
A mapping of theme component keys to CSS properties:
|
|
|
|
```tsx
|
|
type CssJs = Partial<Record<KnownThemeComponents, React.CSSProperties>>;
|
|
```
|
|
|
|
---
|
|
|
|
### PanelGroup
|
|
|
|
Represents a group of configurable theme properties for a component:
|
|
|
|
```tsx
|
|
interface PanelGroup {
|
|
id: string;
|
|
title: string;
|
|
headerSlot?: React.ReactNode;
|
|
classReference?: string;
|
|
inputs: PanelInputProperty[];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### PanelInputProperty
|
|
|
|
An individual configurable CSS property within a panel:
|
|
|
|
```tsx
|
|
interface PanelInputProperty {
|
|
label: string;
|
|
type: 'text' | 'number' | 'color' | 'select';
|
|
value: string;
|
|
prop: string;
|
|
classReference: string;
|
|
unit?: string;
|
|
options?: { label: string; value: string }[];
|
|
placeholder?: string;
|
|
category?: string;
|
|
}
|
|
```
|
|
|
|
## Theme helpers
|
|
|
|
### createTheme
|
|
|
|
Creates a custom theme from scratch (uses `minimal` reset as base):
|
|
|
|
```tsx
|
|
import { createTheme } from '@react-email/editor/plugins';
|
|
|
|
const theme = createTheme({
|
|
body: { backgroundColor: '#1a1a2e', color: '#e2e8f0' },
|
|
button: { backgroundColor: '#3b82f6', color: '#fff' },
|
|
});
|
|
```
|
|
|
|
<ResponseField name="styles" type="ThemeComponentStyles" required>
|
|
CSS-in-JS styles keyed by component name.
|
|
</ResponseField>
|
|
|
|
Returns a `ThemeConfig` object.
|
|
|
|
---
|
|
|
|
### extendTheme
|
|
|
|
Extends a built-in theme with style overrides:
|
|
|
|
```tsx
|
|
import { extendTheme } from '@react-email/editor/plugins';
|
|
|
|
const theme = extendTheme('basic', {
|
|
body: { backgroundColor: '#eff6ff' },
|
|
button: { backgroundColor: '#2563eb', borderRadius: '6px' },
|
|
});
|
|
```
|
|
|
|
<ResponseField name="base" type="EditorTheme" required>
|
|
The built-in theme to extend (`'basic'` or `'minimal'`).
|
|
</ResponseField>
|
|
|
|
<ResponseField name="overrides" type="ThemeComponentStyles" required>
|
|
CSS-in-JS styles to merge on top of the base theme.
|
|
</ResponseField>
|
|
|
|
Returns a `ThemeConfig` object.
|
|
|
|
---
|
|
|
|
## Utility functions
|
|
|
|
### getMergedCssJs
|
|
|
|
Merges the base theme styles with custom panel overrides:
|
|
|
|
```tsx
|
|
import { getMergedCssJs } from '@react-email/editor/plugins';
|
|
|
|
const mergedStyles = getMergedCssJs(theme, panelStyles);
|
|
```
|
|
|
|
<ResponseField name="theme" type="EditorTheme" required>
|
|
The active theme to use as a base.
|
|
</ResponseField>
|
|
|
|
<ResponseField name="panelStyles" type="PanelGroup[]">
|
|
Custom style overrides from the theme panel UI.
|
|
</ResponseField>
|
|
|
|
---
|
|
|
|
### getResolvedNodeStyles
|
|
|
|
Resolves the final CSS styles for a specific node based on theme and document depth:
|
|
|
|
```tsx
|
|
import { getResolvedNodeStyles } from '@react-email/editor/plugins';
|
|
|
|
const styles = getResolvedNodeStyles(node, depth, mergedCssJs);
|
|
```
|
|
|
|
<ResponseField name="node" type="JSONContent" required>
|
|
The TipTap node to resolve styles for.
|
|
</ResponseField>
|
|
|
|
<ResponseField name="depth" type="number" required>
|
|
The node's depth in the document tree. Affects styles for nested elements (e.g., nested lists).
|
|
</ResponseField>
|
|
|
|
<ResponseField name="mergedCssJs" type="CssJs" required>
|
|
The merged theme styles from `getMergedCssJs`.
|
|
</ResponseField>
|
|
|
|
---
|
|
|
|
### getThemeComponentKey
|
|
|
|
Maps a node type and depth to a theme component key:
|
|
|
|
```tsx
|
|
import { getThemeComponentKey } from '@react-email/editor/plugins';
|
|
|
|
const paragraphKey = getThemeComponentKey('paragraph', 0); // 'paragraph'
|
|
const nestedListKey = getThemeComponentKey('bulletList', 2); // 'nestedList'
|
|
```
|
|
|
|
---
|
|
|
|
### stylesToCss
|
|
|
|
Converts a theme's style definitions to a CSS object:
|
|
|
|
```tsx
|
|
import { stylesToCss } from '@react-email/editor/plugins';
|
|
|
|
const css = stylesToCss(styles, theme);
|
|
```
|
|
|
|
---
|
|
|
|
### useEmailTheming
|
|
|
|
React hook that provides access to the current theme state from within the editor:
|
|
|
|
```tsx
|
|
import { useEmailTheming } from '@react-email/editor/plugins';
|
|
|
|
function MyComponent() {
|
|
const theming = useEmailTheming(editor);
|
|
// Access theming.styles, theming.theme, theming.css
|
|
}
|
|
```
|