Add tailwind css to a React app
1. Setup #
tailwind is a popular css utility library. Basically it generates a lot of utility classes intended to be used (mostly) directly in the markup. It uses postcss to generate the css based on an input css.
At the input css you specify what parts of the library you need and also you can add your own styles.
Since it uses postcss, the output of the library can be postprocessed with any of the postcss pluigins ecosystem. In this example we will use a purger to remove all unused classes.
Install #
We'll need the tailwind library, postcss to create the actual css from the library, and postcss-purgecss plugin to remove unused rules in the production build:
npm i -D tailwindcss postcss-cli @fullhuman/postcss-purgecss postcss-import autoprefixer cssnano
Config tailwind #
Create the config files:
npx tailwind init # creates a tailwind.config.js
Add tailwind (minimal) configuration:
tailwind.config.js
:
module.exports = {
theme: {
extend: {},
},
variants: {},
plugins: [],
};
Config postcss #
We add a postcss config file:
touch postcss.config.js
tailwind itself is bundled as a postcss plugin (that takes the previous configuration).
It will generate utility classes based on the input css file.
In a next stage, the purgecss plugin (only run at production) will look for utility clases in the source code (based on the content
options) and remove all unused ones from the generated css.
Here's the magic:
postcss.config.js
:
const purgecss = require("@fullhuman/postcss-purgecss")({
content: ["./src/**/*.tsx"],
defaultExtractor: (content) => content.match(/[A-Za-z0-9-_:/]+/g) || [],
});
const cssnano = require("cssnano")({
preset: "default",
});
const isProd = process.env.NODE_ENV === "production";
module.exports = {
plugins: [
require("postcss-import"),
require("tailwindcss"),
require("autoprefixer"),
isProd && purgecss,
isProd && cssnano,
],
};
npm scripts #
Finally, add some scripts to generate the css.
In this case, we take the css from src/index.css
and generating the output at src/tailwind.css
. I suggest to .gitignore
that output file:
package.json
:
{
"scripts": {
"css": "npm run css:dev",
"css:dev": "postcss src/styles/index.css -o src/styles/output.css",
"css:watch": "postcss src/styles/index.css -o src/styles/output.css -w",
"css:prod": "postcss src/styles/index.css -o src/styles/output.css --env production"
}
}
It's a good idea to add the output file to .gitignore:
.gitignore
:
# tailwind
output.css
2. Usage #
Input css #
Add a file with the input css. Initially it will only contain the tailwind library:
src/styles/index.css
:
@tailwind base;
@tailwind components;
@tailwind utilities;
Import css #
Notice that we import the output file (generated later), not the input:
src/App.jsx
:
import React from "react";
import "./styles/output.css";
const App = () => {
return (
<div className="App">
<FloatingCollapsableWidget>Hello tailwindcss</FloatingCollapsableWidget>
</div>
);
};
3. Test #
Simple example #
Here's an example on how to style a modal and a button:
src/App.jsx
:
import React, { useState } from "react";
export function useCollapsable(title: string): CollapsableModalProps {
const [visible, setVisible] = useState(initialState === "visible");
const toggle = () => setVisible(!visible);
return { title, visible, toggle };
}
export const CollapsableModal = ({ title, children }) => {
const [visible, setVisible] = useState(false);
const toggle = () => setVisible(!visible);
return (
<div className="fixed bottom-0 right-0 p-4 w-100 fade-in">
{visible && (
<div className="bg-white mb-6 rounded shadow-lg z-50 overflow-y-auto">
<div className="flex bg-gray-300 border border-gray-400 border-b-0">
<h1 className="flex-grow p-2">{title}</h1>
<button className="p-2" onClick={toggle}>
{CollapseIcon}
</button>
</div>
{children}
</div>
)}
<div className="flex flex-row-reverse">
<button
className="flex flex-no-wrap bg-gray-700 hover:bg-gray-500 text-white font-bold py-2 px-4 rounded-full"
onClick={toggle}
>
{QuestionIcon}
<p className="leading-6">{visible ? "Close" : "Open"}</p>
</button>
</div>
</div>
);
};
export default FloatingCollapsableWidget;
Generate files #
Run npm run css
to generate the file src/styles/output.css
. The output should be about 1.2MB
Open the app and should see this:
Run npm run css:prod
to generate the same, but including only the used tags. The output is less than 1k (including comments 😂)
🖖