react-email icon indicating copy to clipboard operation
react-email copied to clipboard

Tailwind directives in generated HTML when safelist defined. Breaks styling in Gmail

Open summer-jordan opened this issue 1 year ago • 6 comments

Describe the Bug

When using a custom tailwind config with a safelist, and using responsive tailwind classes, the generated HTML has a style tag with tailwind directives. These directives are invalid CSS which would seem to cause gmail to ignore the style tag entirely.

The directives can be seen in the dev servers code preview pane and in the HTML files generated with the export command.

Dev server Preview

Image

HTML file

Image

When testing emails with an email testing service, some styling was not looking right in some gmail clients. After some debugging, I realized that styles defined in the style tag were only respected when I removed the tailwind directives.

The provided minimal reproduction has 2 emails, one using a custom tailwind config and another that uses the same tailwind config with a safelist added. I have also included the HTML files for both emails generated with the export command.

Which package is affected (leave empty if unsure)

@react-email/tailwind

Link to the code that reproduces this issue

https://github.com/summer-jordan/tw-directive-bug-repro/

To Reproduce

  1. Create a new project with: pnpm create email
  2. Create an email that uses the Tailwind component
  3. Define a tailwind config that has a safelist defined with at least one class
  4. Add a responsive tailwind class to the email: md:p-4 (This is required so that a style tag is created)
  5. Run the dev server and view the HTML preview (directives will be in the style tag)
  6. Run the export command (directives will be in the style tag)

Expected Behavior

There should be no tailwind directives in the HTML.

What's your node version? (if relevant)

22.14.0

summer-jordan avatar Feb 12 '25 22:02 summer-jordan

I want to work on this issue, Would you like to assign me?

abhishek-kumar-91 avatar Feb 15 '25 18:02 abhishek-kumar-91

I wonder why you need to safelist here, it doesn't seem really needed for the email use case. Can you comment on that @summer-jordan?

gabrielmfern avatar Feb 19 '25 13:02 gabrielmfern

Looking at it, the way to go here is to just delete it from the config and warn that the no behavior change will happen because of safelist. safelist doesn't make sense when we talk about inlining most styles, and much less in the email HTML environment.

gabrielmfern avatar Feb 19 '25 13:02 gabrielmfern

I wonder why you need to safelist here, it doesn't seem really needed for the email use case. Can you comment on that @summer-jordan?

We are building a design system for emails using react-email. Keeping in line with our design system for web, we provide props for specifying margin and padding. These props are converted into classes dynamically. Since we do not have the tailwind classes appearing as a single, unbroken string, the spacing classes do not get converted into inline styles unless we add them to the safelist. https://tailwindcss.com/docs/detecting-classes-in-source-files#dynamic-class-names

Since a consumer of the design system could use any of the available spacing classes, we safelist all of them dynamically. We did not want to keep a list of all available spacing classes as that is quite verbose. I will update the code in my reproduction to demonstrate sometime today.

summer-jordan avatar Feb 19 '25 14:02 summer-jordan

@summer-jordan can you make a minmal code example of what you mean here? Because it seems to me like it would work without the safelist as React Email only computes the styles from the final className, not from the code itself like normal TailwindCSS.

gabrielmfern avatar Feb 26 '25 16:02 gabrielmfern

@gabrielmfern I was able to finally test this out and everything seems to work as you described. I removed the safelist in our codebase and all styles were still generated properly. Thank you for your assistance.

summer-jordan avatar Feb 27 '25 19:02 summer-jordan

Its seems this is fixed, can we close it @gabrielmfern 😄

Syed-Umair avatar Jun 09 '25 10:06 Syed-Umair

@Syed-Umair I think we'll keep it open until we have a decided treatment for Tailwind's safe list, most likely throwing an error when it's used.

gabrielmfern avatar Jun 12 '25 12:06 gabrielmfern

We just released a new version that makes safelist a certain no-op and warns when it is enabled in the user's configuration. @react-email/[email protected]/@react-email/[email protected]

gabrielmfern avatar Jul 18 '25 16:07 gabrielmfern