…port
The build-time fix (tsdown plugin to keep the CSS import alive in the
published output) breaks require()/import() of the package's own entry
point for any consumer without a CSS-aware bundler in the loop (plain
Node scripts, Jest without a CSS moduleNameMapper) — it doesn't just
render unstyled anymore, it fails to load at all.
EmailEditor has always shipped this way in every published version;
the docs claimed otherwise. Correct the docs to match the real,
intentional behavior instead: EmailEditor works out of the box but is
unstyled by default, and the theme is a separate opt-in import — the
same pattern the lower-level composable API already documents, and
the same pattern resend.com/blog/react-email-6 describes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
EmailEditoris documented as importing@react-email/editor/themes/default.csson its own, andsrc/email-editor/email-editor.tsxhasimport '../ui/themes/default.css'for that. The import never reaches the published package: tsdown extracts the CSS intodist/style.css, drops the import fromdist/index.mjs/dist/index.cjs, anddist/style.cssis not inexports, so nothing can load it. Every published version ships this way, so<EmailEditor />renders an unstyled bubble menu and slash command menu unless the app imports the theme itself. #3637 reported the orphandist/style.css; #3638 removed the dangling./styles/*export entries but the stylesheet is still unreachable.apps/webdoes not hit this becauseapps/web/src/app/editor/layout.tsximports the theme explicitly.css: { inject: true }from@tsdown/cssis not enough here: it keeps the import in the ESM output but also writes a literalimport './style.css'into the.cjsfile, which breaks the CJS entry. This PR instead adds a small Rolldown plugin totsdown.config.tsthat treats every CSS import undersrc/as external and rewrites it to the matching public entry frompackage.jsonexports.../ui/themes/default.cssbecomes@react-email/editor/themes/default.css, whichscripts/copy-css.tsalready emits intodist/. The build now produces:Only the root entry gets the import; the other subpaths are unchanged,
dist/style.cssis no longer emitted, and importing a CSS file that has noexportsentry fails the build with a message pointing at the import. Nothing undersrc/changes.One consequence to be aware of: Jest setups without a CSS
moduleNameMapper, and plain Node scripts importing@react-email/editorwithout a bundler, will now hit the CSS import on the root entry. If keeping the theme opt-in is preferred, the alternative is to remove the import fromemail-editor.tsx, stop emittingdist/style.css, and update the docs; I can switch the PR to that.Test plan
pnpm build(with dts) andpnpm typecheckinpackages/editorpasspnpm test:unit: 50 files, 502 tests passbiome checkcleanpnpm packand installed it in a Vite + React 19 app with no CSS import of its own: Vite loadsui/themes/default.cssfrom the package and the menus render styled. The same app renders unstyled against the published1.7.2.Summary by cubic
Ships the default theme CSS with
EmailEditorso bubble and slash menus are styled by default. The build now keeps the import in both ESM and CJS by rewriting CSS imports to exported subpaths; previously the import was extracted to an unexported file and menus rendered unstyled unless apps imported@react-email/editor/themes/default.css.package.jsonexports include./themes/default.cssand that only the root entry imports it.dist/style.cssis emitted; the build fails if a CSS import lacks anexportsentry.Written for commit f2c34fb. Summary will update on new commits.