Adding Tailwindcss to Hugo theme

In this tutorial we will be adding Tailwindcss to a new Hugo theme. This assumes that you already have a Hugo theme either an existing one or a new one. If you don't have please see my tutorial on how to create one here.


There are a lot of ways to include Tailwindcss to a Hugo theme but for this tutorial we will have to keep it simple and assume that the Tailwindcss will be a standalone css generator.


Prerequisites


  1. Hugo Site
  2. Hugo Theme
  3. Tailwindcss

If you don't have a Hugo Site and Theme ready, see my other tutorial here for creating a hugo theme.


Setting up Tailwindcss


Run the command below to initialize Tailwindcss in your theme's root directory.


npx tailwindcss init

A tailwind.config.js should be created with contents like below.


/** @type {import('tailwindcss').Config} */
module.exports = {
content: [],
theme: {
    extend: {},
},
plugins: [],
}

Now add the file paths which should use tailwind to the content just like below.


/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
    "./themes/**/layouts/**/*.html",
    "./layouts/**/*.html",
    "../../content/**/*.md" // points to the hugo contents to enable tailwindcss in .md files
],
theme: {
    extend: {},
},
plugins: [],
}

Tailwind uses the content paths to check which css classes are to be purged or retained.
In some cases where we want to use the classes provided by Hugo like in pagination, classes like these that are generated by Hugo will not be included in the final css since Tailwind cannot see this classes on build time thus it will be purged out from the final css file.


To prevent purging out these css classes, we can add safelist to tailwind.config.js just like below.


/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
    "./themes/**/layouts/**/*.html",
    "./layouts/**/*.html",
    // points to the hugo contents to enable tailwindcss in .md files
    "../../content/**/*.md"
],
safelist: [
    '.pagination',
    '.page-item',
    '.page-item.active',
    '.page-item.disabled',
    '.page-item.disabled a'
],
theme: {
    extend: {},
},
plugins: [],
}

Create tailwind.css file in the theme's assets/css/ folder.
You should have something like below.


my-hugo-site/
├── ...
├── themes/
│   └── my-theme/
│       └── assets/
│           └── css/
│               └── main.css
│               └── tailwind.css
└── hugo.toml

Optional: transfer the contents of the main.css into tailwind.css @layer base directive


@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
    ...
}

main.css is used by Hugo internally and it is where we should normally put our css classes and styles, since we are using Tailwindcss to generate a standalone css file we don't need to use any other css file and mess around with Hugo's config just to point it to our new css file, we can just simply create the tailwind.css and add our tailwind styles there and generate its output as main.css


Running Tailwindcss together with Hugo


We can generate a 1 time tailwindcss output with the command below.


# assuming we are currently on the theme's root directory
# if running from hugo site root directory adjust command accordingly
npx tailwindcss -i assets/css/tailwind.css -o assets/css/main.css -c tailwind.config.js --minify

What the above command did is that we take tailwind.css as the input and generate the css file as main.css, and with the --minify flag we simply removed unnecessary white spaces.


During development, it is much better to add the --watch flag to rebuild main.css everytime we updated tailwind.css


Now since we only used vanilla Tailwindcss and Hugo, running both the Hugo server and the Tailwindcss watch command would take up two or more terminals.


To prevent this we can create a script called run_develop.sh (or any other name you would like to use) to run both at the same time and terminate both if we terminate the script, it should look like this.


TAILWIND_INPUT_PATH="themes/my-theme/assets/css/tailwind.css"
TAILWIND_OUTPUT_PATH="themes/my-theme/assets/css/main.css"
TAILWIND_CONFIG_PATH="themes/my-theme/tailwind.config.js"

TAILWIND_COMMAND="npx tailwindcss -i $TAILWIND_INPUT_PATH -o $TAILWIND_OUTPUT_PATH -c $TAILWIND_CONFIG_PATH --minify"
HUGO_COMMAND="hugo server -D --disableFastRender"

# Everytime we run the script, we should delete public folder for a clean build
rm -rf public/
# Same with the generated main.css
rm $TAILWIND_OUTPUT_PATH
# Since we delete main.css, we need to generate main.css again
# before running the server since Hugo will produce some
# unexpected behaviors if main.css is not found
$TAILWIND_COMMAND
# command to run both Hugo and Tailwindcss at the same time and also kill both at the same time
( trap 'kill 0' SIGINT; $HUGO_COMMAND & $TAILWIND_COMMAND --watch )

Script above should be located in Hugo site root directory else it will not work since we also need to run the Hugo server.


We can then run the command below.


./run_develop.sh

Congratulations you should now be able to add tailwind classes to your html files. Everytime an update occurs in tailwind.css or any Hugo files it should automatically regenerate a main.css and or public/ folder from Hugo.