The Tailwind component automatically handles CSS variable resolution, calc() expressions, and inlines styles for maximum email client compatibility.
Installation
npm install @react-email/tailwind tailwindcss
Tailwind Component
Wraps your email content to enable Tailwind CSS utility classes.
import { Tailwind } from '@react-email/tailwind' ;
import { Button } from '@react-email/button' ;
import { Container } from '@react-email/container' ;
export function Email () {
return (
< Tailwind >
< Container className = "bg-white p-8" >
< Button className = "bg-blue-500 text-white px-4 py-2 rounded" >
Click me
</ Button >
</ Container >
</ Tailwind >
);
}
Props
The email components to apply Tailwind styles to
Custom Tailwind configuration. Accepts all Tailwind config options except content. < Tailwind
config = { {
theme: {
extend: {
colors: {
brand: '#007291' ,
},
},
},
} }
>
{ /* Your email content */ }
</ Tailwind >
Basic Usage
import { Html } from '@react-email/html' ;
import { Head } from '@react-email/head' ;
import { Body } from '@react-email/body' ;
import { Tailwind } from '@react-email/tailwind' ;
import { Container } from '@react-email/container' ;
import { Heading } from '@react-email/heading' ;
import { Text } from '@react-email/text' ;
export function WelcomeEmail ({ name } : { name : string }) {
return (
< Html >
< Head />
< Tailwind >
< Body className = "bg-gray-100 font-sans" >
< Container className = "bg-white mx-auto my-8 p-8 rounded-lg" >
< Heading className = "text-2xl font-bold text-gray-900 mb-4" >
Welcome, { name } !
</ Heading >
< Text className = "text-gray-700 text-base mb-4" >
Thank you for joining our platform.
</ Text >
</ Container >
</ Body >
</ Tailwind >
</ Html >
);
}
Custom Configuration
Using Custom Colors
import { Tailwind } from '@react-email/tailwind' ;
const customConfig = {
theme: {
extend: {
colors: {
primary: '#0070f3' ,
secondary: '#7928ca' ,
},
},
},
};
export function Email () {
return (
< Tailwind config = { customConfig } >
< div className = "bg-primary text-white p-4" >
< h1 className = "text-secondary" > Custom Colors </ h1 >
</ div >
</ Tailwind >
);
}
Pixel-Based Preset
For better email client compatibility, use the included pixelBasedPreset which converts rem/em values to pixels.
import { Tailwind , pixelBasedPreset } from '@react-email/tailwind' ;
export function Email () {
return (
< Tailwind config = { pixelBasedPreset } >
< div className = "text-base p-4" >
{ /* text-base = 16px, p-4 = 16px */ }
Content with pixel values
</ div >
</ Tailwind >
);
}
Utility Functions
inlineStyles
Manually extract and inline Tailwind styles for specific class names.
import { inlineStyles , setupTailwind } from '@react-email/tailwind' ;
const setup = await setupTailwind ({});
setup . addUtilities ([ 'bg-blue-500' , 'text-white' , 'p-4' ]);
const styleSheet = setup . getStyleSheet ();
const styles = inlineStyles ( styleSheet , [ 'bg-blue-500' , 'text-white' ]);
// Returns: { backgroundColor: 'rgb(59 130 246)', color: 'rgb(255 255 255)' }
Parameters
The parsed Tailwind CSS stylesheet
Array of Tailwind class names to extract styles for
Returns
Object mapping CSS property names (camelCase) to their values
sanitizeStyleSheet
Processes a stylesheet to resolve CSS variables, calc() expressions, and sanitize declarations for email compatibility.
import { sanitizeStyleSheet } from '@react-email/tailwind' ;
import { parse } from 'css-tree' ;
const styleSheet = parse ( '.example { color: var(--primary); }' );
sanitizeStyleSheet ( styleSheet );
// CSS variables and calc() expressions are now resolved
Parameters
The CSS stylesheet to sanitize (modifies in place)
setupTailwind
Initializes Tailwind CSS compiler with custom configuration.
import { setupTailwind } from '@react-email/tailwind' ;
const tailwind = await setupTailwind ({
theme: {
extend: {
colors: {
brand: '#FF0000' ,
},
},
},
});
// Add utilities for specific classes
tailwind . addUtilities ([ 'bg-brand' , 'text-white' ]);
// Get the compiled stylesheet
const styleSheet = tailwind . getStyleSheet ();
Parameters
Tailwind configuration object (all options except content)
Returns
Object with methods:
addUtilities(candidates: string[]): void - Compile styles for class names
getStyleSheet(): StyleSheet - Get the parsed CSS stylesheet
Email-Specific Considerations
CSS Variable Resolution
The Tailwind component automatically resolves CSS variables (custom properties) since many email clients don’t support them.
// This class uses CSS variables internally
< div className = "bg-blue-500" >
{ /* Automatically converted to: backgroundColor: 'rgb(59 130 246)' */ }
</ div >
Style Inlining
Styles are automatically inlined as much as possible. Non-inlinable styles (media queries, pseudo-classes) are placed in a <style> tag within <head>.
import { Html } from '@react-email/html' ;
import { Head } from '@react-email/head' ;
import { Tailwind } from '@react-email/tailwind' ;
export function Email () {
return (
< Html >
< Head /> { /* Required for non-inlinable styles */ }
< Tailwind >
{ /* Responsive classes need <Head> */ }
< div className = "w-full md:w-1/2" >
Content
</ div >
</ Tailwind >
</ Html >
);
}
If you use responsive utilities (like md:, lg:) or hover states, you must include a <Head> component. The Tailwind component will throw an error if it can’t find one.
Supported Class Types
These classes are converted to inline styles:
Colors: bg-blue-500, text-white
Spacing: p-4, m-2, px-8
Typography: text-lg, font-bold
Layout: flex, block, inline
Sizing: w-full, h-64
Borders: border, border-gray-300, rounded-lg
These classes need a <style> tag in <head>:
Media queries: md:w-1/2, lg:text-xl
Hover states: hover:bg-blue-600
Focus states: focus:outline-none
Pseudo-elements: before:content-['']
Advanced Examples
Responsive Email Layout
import { Html } from '@react-email/html' ;
import { Head } from '@react-email/head' ;
import { Body } from '@react-email/body' ;
import { Tailwind } from '@react-email/tailwind' ;
import { Container } from '@react-email/container' ;
export function ResponsiveEmail () {
return (
< Html >
< Head />
< Tailwind >
< Body className = "bg-gray-50" >
< Container className = "mx-auto p-4" >
{ /* Stack on mobile, side-by-side on desktop */ }
< div className = "w-full md:flex md:gap-4" >
< div className = "w-full md:w-1/2 bg-white p-6 mb-4 md:mb-0" >
< h2 className = "text-xl font-bold mb-2" > Column 1 </ h2 >
< p className = "text-gray-600" > Content </ p >
</ div >
< div className = "w-full md:w-1/2 bg-white p-6" >
< h2 className = "text-xl font-bold mb-2" > Column 2 </ h2 >
< p className = "text-gray-600" > Content </ p >
</ div >
</ div >
</ Container >
</ Body >
</ Tailwind >
</ Html >
);
}
Custom Theme
import { Tailwind , type TailwindConfig } from '@react-email/tailwind' ;
const brandConfig : TailwindConfig = {
theme: {
extend: {
colors: {
brand: {
50 : '#f0f9ff' ,
100 : '#e0f2fe' ,
500 : '#0ea5e9' ,
900 : '#0c4a6e' ,
},
},
fontFamily: {
sans: [ 'Inter' , 'Arial' , 'sans-serif' ],
},
},
},
};
export function BrandedEmail () {
return (
< Tailwind config = { brandConfig } >
< div className = "bg-brand-50 font-sans" >
< h1 className = "text-brand-900" > Hello </ h1 >
< button className = "bg-brand-500 text-white px-6 py-3" >
Action
</ button >
</ div >
</ Tailwind >
);
}
Dark Mode Support
import { Html } from '@react-email/html' ;
import { Head } from '@react-email/head' ;
import { Tailwind } from '@react-email/tailwind' ;
export function DarkModeEmail () {
return (
< Html >
< Head />
< Tailwind >
< div className = "bg-white dark:bg-gray-900 text-gray-900 dark:text-white p-8" >
< h1 className = "text-2xl mb-4" > Adapts to Dark Mode </ h1 >
< p className = "text-gray-700 dark:text-gray-300" >
This email respects your email client's color scheme.
</ p >
</ div >
</ Tailwind >
</ Html >
);
}
TypeScript
import { Tailwind , type TailwindConfig , type TailwindProps } from '@react-email/tailwind' ;
import type { ReactNode } from 'react' ;
interface EmailWrapperProps {
children : ReactNode ;
config ?: TailwindConfig ;
}
function EmailWrapper ({ children , config } : EmailWrapperProps ) {
return (
< Tailwind config = { config } >
{ children }
</ Tailwind >
);
}
Best Practices
Always include <Head> for responsive classes
Media queries and pseudo-classes require a <head> element to inject non-inlinable styles. < Html >
< Head /> { /* Required! */ }
< Tailwind >
< div className = "md:w-1/2" > Content </ div >
</ Tailwind >
</ Html >
Use pixel-based values for better compatibility
Some email clients don’t support rem/em units. Use the pixelBasedPreset or configure custom pixel values. import { Tailwind , pixelBasedPreset } from '@react-email/tailwind' ;
< Tailwind config = { pixelBasedPreset } >
< div className = "text-base" > { /* 16px instead of 1rem */ }
Content
</ div >
</ Tailwind >
Email clients have limited CSS support. Stick to simple flexbox/table layouts and avoid complex positioning. // Good: Simple flex layout
< div className = "flex gap-4" >
< div className = "flex-1" > Column 1 </ div >
< div className = "flex-1" > Column 2 </ div >
</ div >
// Avoid: Complex grid or absolute positioning
< div className = "grid grid-cols-3 gap-4 relative" >
< div className = "absolute top-0 left-0" > ... </ div >
</ div >
Test across email clients
Tailwind classes are converted to inline styles, but rendering can vary. Test your emails in multiple clients (Gmail, Outlook, Apple Mail, etc.).
Troubleshooting
Error: Cannot find <head> element
This error occurs when using non-inlinable classes (media queries, hover states) without a <Head> component. Solution : Add <Head /> inside your email structure:import { Head } from '@react-email/head' ;
< Html >
< Head />
< Tailwind >
{ /* Your content */ }
</ Tailwind >
</ Html >
Make sure:
The className prop is supported by the component
Class names are spelled correctly
Custom classes are defined in your config
// Verify component supports className
import { Button } from '@react-email/button' ;
< Button className = "bg-blue-500" > { /* ✓ Supported */ }
Click
</ Button >