When using Tailwind CSS with Module Federation, you may encounter an issue where Tailwind classes used in your remote applications don't render correctly. This guide explains why this happens and how to configure your workspace to resolve it.
Understanding the Problem
Section titled “Understanding the Problem”Tailwind CSS uses a content scanning mechanism to determine which CSS classes to include in your final stylesheet. During the build process, Tailwind scans the files specified in your configuration and only generates CSS for the classes it finds. This is how Tailwind keeps your CSS bundle small by eliminating unused styles.
In a Module Federation architecture, the host and remote applications are built independently. When the host application builds, Tailwind only scans the host's source files—it has no knowledge of the classes used in remote applications. As a result, when remotes are loaded at runtime, any Tailwind classes they use that aren't also used in the host will be missing from the stylesheet.
Configuring the Host Application
Section titled “Configuring the Host Application”The solution is to configure your host application's Tailwind setup to include the source files from your remote applications. This ensures all Tailwind classes used across your federated application are compiled into the host's stylesheet.
Tailwind CSS v4
Section titled “Tailwind CSS v4”For Tailwind CSS v4, use the @source directive in your stylesheet to include remote application paths:
@import 'tailwindcss';
/* Include shared libraries */@source "../../../libs";
/* Include remote applications */@source "../remote1/src";@source "../remote2/src";@import 'tailwindcss';
/* Include shared libraries */@source "../../../libs";
/* Include remote applications */@source "../remote1/src";@source "../remote2/src";Tailwind CSS v3
Section titled “Tailwind CSS v3”For Tailwind CSS v3, configure the content array in your host's tailwind.config.js to include glob patterns for your remote applications:
const { join } = require('path');
module.exports = { content: [ join(__dirname, '{src,pages,components,app}/**/*.{ts,tsx,js,jsx}'), // Include shared libraries join(__dirname, '../../libs/**/*.{ts,tsx,js,jsx}'), // Include remote applications join(__dirname, '../remote1/src/**/*.{ts,tsx,js,jsx}'), join(__dirname, '../remote2/src/**/*.{ts,tsx,js,jsx}'), ], theme: { extend: {}, }, plugins: [],};const { join } = require('path');
module.exports = { content: [ join(__dirname, 'src/**/*.{ts,html}'), // Include shared libraries join(__dirname, '../../libs/**/*.{ts,html}'), // Include remote applications join(__dirname, '../remote1/src/**/*.{ts,html}'), join(__dirname, '../remote2/src/**/*.{ts,html}'), ], theme: { extend: {}, }, plugins: [],};Adjust the paths based on your workspace structure. If your remotes are in different directories, update the glob patterns accordingly.
Shared Theme Extensions
Section titled “Shared Theme Extensions”If your remote applications use custom Tailwind theme extensions (such as custom colors, fonts, or spacing values), you need to ensure these are also defined in the host's Tailwind configuration. Otherwise, classes like bg-brand-primary or text-custom-lg won't generate any CSS.
Consider creating a shared Tailwind preset that all applications can extend:
module.exports = { theme: { extend: { colors: { brand: { primary: '#3b82f6', secondary: '#10b981', }, }, }, },};Then use this preset in both your host and remote configurations:
const sharedPreset = require('../../libs/shared/tailwind-preset/src');
module.exports = { presets: [sharedPreset], content: [ // ... your content configuration ],};