How to add TailwindCSS to your Hugo site
Tags: hugo, go, tailwindcss, postcss
Published: 2021-01-03 06:57:40

*Originally posted on [divrhino.com](https://divrhino.com/articles/add-tailwindcss-to-hugo/)*

{% youtube 8Hr19zVHCbo %}

Tailwind is a utility CSS library that has been gaining a lot of popularity in the past few years. Utility libraries are great because you won't end up fighting against a framework when it comes to building your own custom designs. And with Tailwind, you can build your sites faster because you won't be jumping between your HTML and CSS all the time. In this tutorial, we're going to learn how to add TailwindCSS to a Hugo project.

## Prerequisites

To follow along with this tutorial, you will need to have **Hugo** and **NodeJS** installed

Installation guides:

- Hugo: [https://gohugo.io/getting-started/installing/](https://gohugo.io/getting-started/installing/)
- NodeJS: [https://nodejs.org/en/download/](https://nodejs.org/en/download/)

## Creating Hugo project and theme

Let's start by creating a new project. Navigation into the directory where you keep all your projects, and run the command to create a new hugo site. We're going to name our site *"hugotails"*.

```bash
cd Sites
hugo new site hugotails
```

Then change directories into our new *"hugotails"* site and create a new theme. We will call the theme *"windytheme"*.

```bash
cd hugotails

hugo new theme windytheme
```

## Initialising NPM and installing dependencies

Now that we've got our hugo site all ready to go, let's install tailwind. To follow along with this section of the tutorial, you will need to have Nodejs installed. So if you haven't installed it already, you might want to do so before continuing.


Make sure you're in the *"hugotails"* project root because we will be initialising NPM here. We can run the `npm init` command with the `--yes` flag so we don't have to go through all the setup questions.

After this command is successfully run, we will have a newly-created `package.json` in our project root.

```bash
npm init --yes
```

Now that our project has been initialised with NPM, we can go ahead and install the necessary packages. Run:

```bash
npm install --save-dev autoprefixer postcss postcss-cli postcss-import tailwindcss
```

We are passing in the `-save-dev` flag because we want to save these packages as dev dependencies.

If you noticed, we aren't just installing the tailwind package, we have a few other accompanying packages. Below is a brief description of what each of them are for:

1. `Postcss` - a tool for transforming CSS with JavaScript.
2. `postcss-cli` - the command-line tool we can use to execute Postcss commands in the terminal
3. `postcss-import` - used to resolve the path of an @import rule
4. `autoprefixer` - helps us add vendor prefixes to our CSS
5. `tailwindcss` - a library of utility classes to help us build unique custom layouts without doing too much

## Setting up config files

Next up, we will tell our site to use our new `windytheme` theme, by adding the following line to our `hugotails/config.toml` file:

```toml
...
theme = "windytheme"
```

 Now we can move onto adding tailwind as a PostCSS plugin. Since we're working with a brand new theme, we don't have a `css` directory yet. Let's create one. Running mkdir with the `-p` flag will create nested directories if they don't already exist.

```bash
mkdir -p themes/windytheme/assets/css/
```
Next we need to create configuration files for both PostCSS and tailwind. We will also need a main `styles.scss` file:

```bash
touch themes/windytheme/assets/css/postcss.config.js
touch themes/windytheme/assets/css/tailwind.config.js
touch themes/windytheme/assets/css/styles.scss
```

Let's tackle the postcss config first. Open up the `postcss.config.js` file

```javascript
const themeDir = __dirname + '/../../';

module.exports = {    
    plugins: [   
        require('postcss-import')({
            path: [themeDir]
            }), 
        require('tailwindcss')(themeDir + 'assets/css/tailwind.config.js'),
        require('autoprefixer')({
            path: [themeDir]
        }),
    ]
}
```

Phew, that was a lot. But we're not done yet, let's head over to our `tailwind.config.js` and add a basic configuration file for TailwindCSS:

```javascript
const themeDir = __dirname + '/../../';

module.exports = {
  content: [
    `${themeDir}/layouts/**/*.html`, 
    `${themeDir}/content/**/*.md`
  ],
  theme: {
    extend: {}
  },
  variants: {},
  plugins: []
}
```

## Updating styles.scss

Now we have to include the necessary tailwind imports in our stylesheet. Open up our stylesheet, `styles.scss`, and add the following imports:

```scss
@import "node_modules/tailwindcss/base";
@import "node_modules/tailwindcss/components";
@import "node_modules/tailwindcss/utilities";
```

## Importing CSS in head tag

When we created our new theme, Hugo helped us out by creating some starting templates files. One of these starter files is the `head.html` partial. 

```html
{{ $time := now }}
{{ $styles := resources.Get "css/styles.scss"
    | toCSS
    | postCSS (dict "config" "./assets/css/postcss.config.js")
    | resources.ExecuteAsTemplate (printf "styles.%s.css" $time) $time
}}

{{ if .Site.IsServer }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}">
{{ else }}
    {{ $styles := $styles | minify | fingerprint | resources.PostCSS }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}">
{{ end }}
```

So what's going on in our code above? Let's go over it line-by-line:

- `{{ $time := now }}` - We’re getting the current time so we can use to bust our cache in local development
- `$styles := resources.Get "css/styles.scss"` - We got our stylesheet as a resource and stored it in a variable called styles
- `| toCSS` - We used Hugo pipes to first convert the SCSS file to CSS, so the browser can understand it
- `| postCSS (dict "config" "./assets/css/postcss.config.js")` - We point to where our PostCSS config file lives
- `| resources.ExecuteAsTemplate (printf "styles.%s.css" $time) $time` - We execute our stylesheet as a template so we can append a timestamp to the end of the filename
- We're going to check if we're in our local dev environment by using the IsServer variable, if we are, we will link to the stylesheets relative URL
- However, if we're in a production environment, we're going to use Hugo Pipes to minify our css file
- We also want to pipe it through fingerprint so that we know the asset has not been tampered with. This also has a nice side-effect of cache-busting, so we also know we're serving the latest version

## Testing some TailwindCSS classes

We've set up all the configuration we need. Now let's set up our `index` page too. This file can be found at `themes/windytheme/layouts/index.html`.

```html
{{ define "main" }}
  {{ .Content }}
{{ end }}
```

Now we can imported our styles and transformed them in a few useful ways, let's see if everything actually works.

Let's create a basic header in the `themes/windytheme/layouts/partials/header.html` file:

```html
<header>
  <h1>Welcome to HugoTails!</h1>
</header>
```

While still in `themes/windytheme/layouts/partials/header.html`, let's add some tailwind utility classes:

```html
<header class="w-full bg-red-300">
  <h1 class="text-center">Welcome to HugoTails!</h1>
</header>
```

We should also start our Hugo server:

```bash
hugo server
```

Open your browser and visit [http://localhost:1313](), you should be able to see your changes there.

## Conclusion

In this tutorial, you learnt how to add tailwindcss to your hugo site using Hugo Pipes. If you enjoyed this article and you'd like more, consider following [Div Rhino on YouTube](https://www.youtube.com/watch?v=4VSno5bK9Uk).

Congratulations, you did great. Keep learning and keep coding!

{% github divrhino/hugotails %}