Let me help you understand the setup needed for sharing Tailwind-styled components across multiple applications:
When you have a shared library with Tailwind-styled components that you want to use in multiple applications, you'll need to:
- In your shared library:
- Install Tailwind as a dependency
- Configure Tailwind in your library's
tailwind.config.js
- Make sure your library's built CSS gets included in the package
- In both consuming applications:
- Yes, you do need to install Tailwind in both applications
- Configure Tailwind in each application's
tailwind.config.js
- Add your library's path to the
content
array in the Tailwind config
Here's an example setup:
// In your library's tailwind.config.js
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
// In each consuming application's tailwind.config.js
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
// Add path to your library's components
'./node_modules/your-library/dist/**/*.{js,jsx,ts,tsx}'
],
theme: {
extend: {},
},
plugins: [],
}
The reason you need Tailwind installed in both applications is that:
- Tailwind needs to scan your code at build time to generate the CSS
- Each application might use different Tailwind classes outside your library
- Each application needs to process and purge unused styles
To ensure consistent styling:
- Make sure all projects use the same Tailwind version
- Consider using a shared Tailwind config that all projects extend
- Be cautious with customizations in individual projects as they might affect the library's components
Would you like me to provide more specific configuration examples for your use case?
I'll help you create a complete example of a shared component library with Tailwind and how to extend its configuration.
First, let's set up the library:
// library/tailwind.config.js
module.exports = {
prefix: 'lib-', // Optional: to avoid class name conflicts
theme: {
extend: {
colors: {
primary: {
100: '#E6F7FF',
500: '#1890FF',
900: '#003A8C',
},
},
spacing: {
'custom': '32rem',
}
}
}
}
Let's create a sample button component in your library:
// library/src/components/Button.tsx
import React from 'react';
export interface ButtonProps {
variant?: 'primary' | 'secondary';
children: React.ReactNode;
}
export const Button = ({ variant = 'primary', children }: ButtonProps) => {
const baseClasses = 'lib-px-4 lib-py-2 lib-rounded-md lib-font-medium lib-transition-colors';
const variantClasses = {
primary: 'lib-bg-primary-500 lib-text-white hover:lib-bg-primary-900',
secondary: 'lib-bg-primary-100 lib-text-primary-500 hover:lib-bg-primary-200'
};
return (
<button className={`${baseClasses} ${variantClasses[variant]}`}>
{children}
</button>
);
};
Now, in your consuming application, here's how you would extend the library's configuration:
// app/tailwind.config.js
const libraryConfig = require('your-library/tailwind.config.js');
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'./node_modules/your-library/**/*.{js,jsx,ts,tsx}'
],
theme: {
extend: {
...libraryConfig.theme.extend,
// Add app-specific extensions
colors: {
...libraryConfig.theme.extend.colors,
// Override or add new colors
secondary: {
500: '#722ED1',
}
}
}
}
}
To use the component in your application:
// app/src/App.tsx
import { Button } from 'your-library';
function App() {
return (
<div className="p-4">
<Button variant="primary">Library Button</Button>
</div>
);
}
To make this work properly, you'll need to set up your library's package.json correctly:
// library/package.json
{
"name": "your-library",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"tailwind.config.js"
],
"peerDependencies": {
"react": "^18.0.0",
"tailwindcss": "^3.0.0"
},
"dependencies": {
"classnames": "^2.3.1"
},
"devDependencies": {
"tailwindcss": "^3.0.0",
// ... other dev dependencies
}
}
Key points to ensure styles work correctly:
- Export your library's Tailwind config:
// library/src/index.ts
export * from './components/Button';
export { default as tailwindConfig } from './tailwind.config';
- In your library's build process, make sure to:
- Compile your TypeScript/JavaScript
- Process your CSS with Tailwind
- Include your Tailwind config in the distribution
- In your consuming application:
- Install both your library and tailwindcss as dependencies
- Import your library's components
- Configure Tailwind to scan your library's components
- Extend the library's Tailwind configuration
This setup ensures that:
- Your library's styles are consistently applied across different applications
- Applications can override or extend the library's styling if needed
- The prefix ('lib-') prevents class name conflicts
- Tailwind's purge process correctly identifies and includes the necessary styles
Would you like me to elaborate on any part of this setup or show how to handle more complex styling scenarios?
If you're using CSS custom properties (root variables) in your library, you'll need to handle them carefully to ensure they're available across all applications. Here's how to set it up:
In your library:
/* library/src/styles/base.css */
:root {
--lib-primary-color: #1890FF;
--lib-secondary-color: #722ED1;
--lib-text-color: #2C3E50;
--lib-spacing-sm: 0.5rem;
--lib-spacing-md: 1rem;
--lib-spacing-lg: 1.5rem;
}
/* You can also define dark mode variables */
@media (prefers-color-scheme: dark) {
:root {
--lib-primary-color: #40A9FF;
--lib-text-color: #ECF0F1;
}
}
Then use these variables in your Tailwind config:
// library/tailwind.config.js
module.exports = {
prefix: 'lib-',
theme: {
extend: {
colors: {
primary: 'var(--lib-primary-color)',
secondary: 'var(--lib-secondary-color)',
text: 'var(--lib-text-color)',
},
spacing: {
sm: 'var(--lib-spacing-sm)',
md: 'var(--lib-spacing-md)',
lg: 'var(--lib-spacing-lg)',
}
}
}
}
In your component:
// library/src/components/Button.tsx
import React from 'react';
import '../styles/base.css'; // Import base styles
export const Button = ({ children }) => {
return (
<button className="lib-bg-primary lib-text-text lib-p-md">
{children}
</button>
);
};
Make sure to export your base CSS:
// library/src/index.ts
export * from './components/Button';
export { default as tailwindConfig } from './tailwind.config';
import './styles/base.css';
In your consuming application, you can override these variables:
/* app/src/styles/variables.css */
:root {
/* Override library variables */
--lib-primary-color: #3498DB;
/* Add application-specific variables */
--app-accent-color: #E74C3C;
}
And in your application's Tailwind config:
// app/tailwind.config.js
const libraryConfig = require('your-library/tailwind.config.js');
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'./node_modules/your-library/**/*.{js,jsx,ts,tsx}'
],
theme: {
extend: {
...libraryConfig.theme.extend,
// Add app-specific colors that can use library variables
colors: {
...libraryConfig.theme.extend.colors,
accent: 'var(--app-accent-color)'
}
}
}
}
Some important considerations:
- Prefix your library's CSS variables to avoid conflicts:
/* Good */
--lib-primary-color: #1890FF;
/* Could conflict with app variables */
--primary-color: #1890FF;
- Document your CSS variables:
/**
* Library CSS Variables
* --lib-primary-color: Main brand color
* --lib-secondary-color: Secondary brand color
* --lib-text-color: Default text color
* --lib-spacing-sm: Small spacing unit (0.5rem)
* --lib-spacing-md: Medium spacing unit (1rem)
* --lib-spacing-lg: Large spacing unit (1.5rem)
*/
- Consider providing a CSS reset in your library:
/* library/src/styles/reset.css */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Only if you want to enforce specific baseline styles */
- Make sure your build process handles CSS files:
// library/rollup.config.js or webpack.config.js
{
plugins: [
postcss({
extract: 'styles.css',
modules: false,
use: ['sass'], // if using Sass
})
]
}
This setup gives you the flexibility to:
- Define default styles in your library
- Allow applications to override these defaults
- Keep styles consistent across applications
- Maintain dark mode support
- Add application-specific customizations
Would you like me to elaborate on any of these aspects or show how to handle more complex scenarios with CSS variables?
If you're using rollup (rslib) for your library, here's how to handle multiple components and their styles efficiently:
First, let's organize your library structure:
library/
├── src/
│ ├── components/
│ │ ├── Button/
│ │ │ ├── Button.tsx
│ │ │ └── button.css
│ │ ├── Card/
│ │ │ ├── Card.tsx
│ │ │ └── card.css
│ ├── styles/
│ │ ├── base.css
│ │ └── variables.css
│ └── index.ts
├── rollup.config.js
└── package.json
Your main entry file should export everything:
// src/index.ts
export * from './components/Button/Button';
export * from './components/Card/Card';
// Import all styles at the root level
import './styles/variables.css';
import './styles/base.css';
Configure rollup to handle CSS files:
// rollup.config.js
import typescript from '@rollup/plugin-typescript';
import postcss from 'rollup-plugin-postcss';
import autoprefixer from 'autoprefixer';
import tailwindcss from 'tailwindcss';
export default {
input: 'src/index.ts',
output: [
{
dir: 'dist',
format: 'esm',
preserveModules: true, // This keeps your file structure
preserveModulesRoot: 'src'
}
],
plugins: [
typescript(),
postcss({
plugins: [
tailwindcss(),
autoprefixer()
],
extract: 'styles.css', // This will extract all CSS into one file
minimize: true,
modules: false // Set to true if you want CSS modules
})
],
external: ['react', 'react-dom'] // Add other external dependencies
}
Update your package.json:
{
"name": "your-library",
"version": "1.0.0",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"tailwind.config.js"
],
"style": "dist/styles.css",
"sideEffects": [
"**/*.css"
]
}
Then in your consuming application, you only need to import the library once:
// app/src/App.tsx
import 'your-library/dist/styles.css';
import { Button, Card } from 'your-library';
For Tailwind, make sure your library's tailwind.config.js is properly configured:
// library/tailwind.config.js
module.exports = {
prefix: 'lib-',
content: [
'./src/**/*.{js,jsx,ts,tsx}'
],
theme: {
extend: {
// Your theme extensions
}
}
}
If you want to provide more granular control over styles, you could also export them separately:
// src/index.ts
export * from './components/Button/Button';
export * from './components/Card/Card';
// Export styles separately if needed
export { default as baseStyles } from './styles/base.css';
export { default as variables } from './styles/variables.css';
Key points to remember:
- Set
sideEffects: ["**/*.css"]
in package.json to prevent CSS from being tree-shaken - Use
preserveModules: true
in rollup config to maintain your file structure - Consider using CSS modules if you need scoped styles
- Make sure all your CSS files are processed by postcss and Tailwind
- Export your Tailwind config so consuming apps can extend it
Would you like me to explain any part in more detail or show how to handle specific scenarios with rslib?