You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, the <Tailwind> component only supports customization through the config prop. This requires developers to use JavaScript objects to define their theme. However, with Tailwind CSS v4 introducing CSS-based configuration through @theme, @plugin and @utility directives, there is an opportunity to provide a more modern and flexible approach.
The existing config prop works well but can be a step backward for applications already building their themes using CSS. Personally, I found this quite inconvenient. My web app and design system were built on top of Tailwind v4 with configurations entirely in CSS. To introduce react-email, I had to step back and perform a "big bang" refactor of my application's styling architecture just to accommodate the library.
Proposal
Warning
Please do not get too attached to the specific API proposal below. I am sharing the core idea, and alternative API suggestions are very welcome.
I propose adding a new optional theme prop to the <Tailwind> component that accepts a CSS string containing @theme directives:
This approach aligns with the direction of Tailwind CSS v4. While it could eventually support other directives like @utility, starting with @theme provides immediate value without the overhead of complex CSS parsing into an AST.
Community Discussion
I would love to hear your thoughts on how we can evolve this. Some open questions:
How can we design an elegant API that prevents confusion between the config and theme props?
What is the best way to support other directives, such as @plugin and @utility, without introducing significant parsing overhead?
What is the most efficient way to pass this information to the component: serializing the CSS, or is there a better alternative?
Git Patch
Here is an initial version of this idea. You can test it by applying this patch via git apply changes.patch.
Details
diff --git a/packages/tailwind/src/tailwind.tsx b/packages/tailwind/src/tailwind.tsx
index a4462553..a81a22fd 100644
--- a/packages/tailwind/src/tailwind.tsx+++ b/packages/tailwind/src/tailwind.tsx@@ -10,11 +10,13 @@ import { mapReactTree } from './utils/react/map-react-tree';
import { cloneElementWithInlinedStyles } from './utils/tailwindcss/clone-element-with-inlined-styles';
import { setupTailwind } from './utils/tailwindcss/setup-tailwind';
+export type CSSTheme = string;
export type TailwindConfig = Omit<Config, 'content'>;
export interface TailwindProps {
children: React.ReactNode;
config?: TailwindConfig;
+ theme?: CSSTheme;
}
export interface EmailElementProps {
@@ -82,10 +84,10 @@ export const pixelBasedPreset: TailwindConfig = {
},
};
-export function Tailwind({ children, config }: TailwindProps) {+export function Tailwind({ children, config, theme }: TailwindProps) {
const tailwindSetup = useSuspensedPromise(
- () => setupTailwind(config ?? {}),- JSON.stringify(config, (_key, value) =>+ () => setupTailwind(config ?? {}, theme ?? ''),+ JSON.stringify({ config, theme }, (_key, value) =>
typeof value === 'function' ? value.toString() : value,
),
);
diff --git a/packages/tailwind/src/utils/tailwindcss/setup-tailwind.ts b/packages/tailwind/src/utils/tailwindcss/setup-tailwind.ts
index fc1ec69b..f61f3cc9 100644
--- a/packages/tailwind/src/utils/tailwindcss/setup-tailwind.ts+++ b/packages/tailwind/src/utils/tailwindcss/setup-tailwind.ts@@ -1,6 +1,6 @@
import { parse, type StyleSheet } from 'css-tree';
import { compile } from 'tailwindcss';
-import type { TailwindConfig } from '../../tailwind';+import type { CSSTheme, TailwindConfig } from '../../tailwind';
import indexCss from './tailwind-stylesheets/index';
import preflightCss from './tailwind-stylesheets/preflight';
import themeCss from './tailwind-stylesheets/theme';
@@ -8,13 +8,15 @@ import utilitiesCss from './tailwind-stylesheets/utilities';
export type TailwindSetup = Awaited<ReturnType<typeof setupTailwind>>;
-export async function setupTailwind(config: TailwindConfig) {+export async function setupTailwind(config: TailwindConfig, theme: CSSTheme) {
const baseCss = `
@layer theme, base, components, utilities;
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/utilities.css" layer(utilities);
+@import "custom-theme.css" layer(theme);
@config;
`;
+
const compiler = await compile(baseCss, {
async loadModule(id, base, resourceHint) {
if (resourceHint === 'config') {
@@ -63,6 +65,14 @@ export async function setupTailwind(config: TailwindConfig) {
};
}
+ if (id === 'custom-theme.css') {+ return {+ base,+ path: id,+ content: theme,+ };+ }+
throw new Error(
'stylesheet not supported, you can only import the ones from tailwindcss',
);
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Background
Currently, the
<Tailwind>component only supports customization through theconfigprop. This requires developers to use JavaScript objects to define their theme. However, with Tailwind CSS v4 introducing CSS-based configuration through@theme,@pluginand@utilitydirectives, there is an opportunity to provide a more modern and flexible approach.The existing
configprop works well but can be a step backward for applications already building their themes using CSS. Personally, I found this quite inconvenient. My web app and design system were built on top of Tailwind v4 with configurations entirely in CSS. To introducereact-email, I had to step back and perform a "big bang" refactor of my application's styling architecture just to accommodate the library.Proposal
Warning
Please do not get too attached to the specific API proposal below. I am sharing the core idea, and alternative API suggestions are very welcome.
I propose adding a new optional
themeprop to the<Tailwind>component that accepts a CSS string containing@themedirectives:This approach aligns with the direction of Tailwind CSS v4. While it could eventually support other directives like
@utility, starting with@themeprovides immediate value without the overhead of complex CSS parsing into an AST.Community Discussion
I would love to hear your thoughts on how we can evolve this. Some open questions:
configandthemeprops?@pluginand@utility, without introducing significant parsing overhead?Git Patch
Here is an initial version of this idea. You can test it by applying this patch via
git apply changes.patch.Details
Beta Was this translation helpful? Give feedback.
All reactions