SW engineering, engineering management and the business of software

subscribe for more
stuff like this:

Plain old HTML Tailwind CSS projects

Tailwind has quickly become my favorite CSS framework. One quirk of working with tailwind is that the core framework is massive. You need a proper npm or yarn setup and tree shaking via purgeCSS is necessary for any kind of production usage. You can see some numbers at the end of this post, but spoiler: 3 orders of magnitude reduction in CSS size is normal and necessary to get your CSS file to a reasonable size.

Tailwind is fantastic when paired with front end app frameworks such as Vue, React, etc. I don’t always need a front-end app framework however and simple html works fine for certain work.

It turns out that this is just a little fiddly and you can quite easily make “plain old html” projects work just fine with Tailwind.

Here’s how I do it:

Starting From Scratch

First, some basic setup:

mkdir -p site/static/css

site is where our plan old html will live. site/static is a great place for images, css and other files that don’t change.

Conceptually, site doesn’t even have to be even in the project directory, if you make the necessary adjustments to the appropriate config files.

npm init
npm install --save-dev tailwindcss
npm install --save-dev @tailwindcss/typography
npm install --save-dev cssnano
npm install --save-dev @fullhuman/postcss-purgecss 
npm install postcss-cli --global

Next, you need a basic input.css file.

Create this at the root of your project directory (where you ran npm init).

touch site/static/css/input.css

It should contain the following three lines:

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

Basic Config

You need a few config files. What’s a modern frontend project these days without a mountain of config?

I use two different postcss config files depending on whether I want to minify or not.

mkdir build debug
touch /build/postcss.config.js
touch /debug/postcss.config.js

/build/postcss.config.js should contain the following:

module.exports = {
  plugins: [
    // ...

/debug/postcss.config.js is the same, but remove the require('cssnano') line

touch tailwind.config.js

tailwind.config.js should contain the following:

module.exports = {
  purge: {
    enabled: true,
    content: [
  theme: {
    extend: {},
  variants: {},
  plugins: [

Lastly, open up package.json and add the following scripts:

"scripts": {
    "debug": "postcss site/static/css/input.css --verbose --config debug --output site/static/css/style.css",
    "build": "postcss site/static/css/input.css --verbose --config build --output site/static/css/style.css"

You can do either of the following to generate CSS:

npm run debug   # generate, purge, but don't minify
npm run build   # generate, purge, minify

Purging can sometimes be finicky and I don’t recommend you turn it off, even in during dev or debug mode.

At this point, any html files you add to the site directory should be scanned during the purgeCSS processing.

Your style.css file should contain only relevant tailwind CSS classes.

A quick size check, using a minimal hello world HTML file:

  • Tailwind CSS, not purged, not minified: 2.4 MB
  • Tailwind CSS, not purged, minified: 1.9 MB
  • Tailwind CSS, purged, not minified: 12 kb
  • Tailwind CSS, purged, minified: 3 kb

Plain Old HTML

I love POH for simple pages. It’s rarely worth the effort to setup an entire vue or react project for something like a landing page or placeholder work. For me, it’s almost always worth the effort to get tailwind in place.

in lieu of comments, you should follow me on twitter at twitter/amattn and on twitch.tv at twitch.tv/amattn. I'm happy to chat about content here anytime.

the fine print:
aboutarchivemastodontwittertwitchconsulting or speaking inquiries
© matt nunogawa 2010 - 2023 / all rights reserved