Supercharge Your HTML&CSS Workflow With Pug and TailwindCSS
Tags: webdev, html, css, tailwindcss
Published: 2023-03-03 21:00:00

Coding in HTML and CSS can be time-consuming. For large HTML and CSS files, they can be hard to maintain as well.

A much better approach is to use **HTML templating languages**, such as [Pug](https://pugjs.org/api/getting-started.html) and **CSS frameworks**, such as [Tailwind CSS](https://tailwindcss.com/), to _generate your HTML and CSS code_ on the fly.

In this tutorial, I'll show you how to bootstrap such a project in no time using the [create-pug-tailwindcss-app](https://www.npmjs.com/package/create-pug-tailwindcss-app) package I built and how to really leverage the power of Pug and Tailwind CSS to make your life easier.

---

## Table of Contents

- [Prerequisites](#prerequisites)
- [How Pug Works](#how-pug-works)
- [How Tailwind CSS Works](#how-tailwind-css-works)
- [Build an Example in <10 Minutes](#build-an-example-in-10-minutes)
  - [Get Started](#get-started)
  - [Pug to HTML](#pug-to-html)
  - [Add Tailwind CSS Classes](#add-tailwind-css-classes)
  - [Go to Production](#go-to-production)
- [Conclusion](#conclusion)

---


## Prerequisites

- You're expected to have basic knowledge about HTML templating languages. If not, I have a [post](https://dev.to/jessewei/pug-a-html-templating-language-3oe2) covering the basics of Pug so feel free to check it out. You can also take a look at the [official docs of Pug](https://pugjs.org/api/getting-started.html). I'll cover some more advanced usage of Pug in this tutorial too.
- You're expected to have basic knowledge about Tailwind CSS. If not,  check out its [official docs](https://tailwindcss.com/), especially the [Get Started](https://tailwindcss.com/docs/installation) and [Core Concepts](https://tailwindcss.com/docs/utility-first) sections. They also have an [interactive playground](https://play.tailwindcss.com/) where you can try Tailwind CSS out easily.
- I use [VSCode](https://code.visualstudio.com/) as my editor  with the [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) extension installed. Any other editors that the extension supports should work as well. But if there's no compatible Live Server extension for your editor, you'd need to do a bit research to find a dev server with hot reload support.

---


## How Pug Works

Pug is a templating language that when compiled, outputs HTML code. So instead of writing HTML directly, you write Pug code and then compile it to generate HTML.

For example, this Pug snippet,

```pug
doctype html
html
  head
    title My Site
  body
    h1 Hello, World!
    p This is my site.
```

generates the following HTML:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>My Site</title>
  </head>
  <body>
    <h1>Hello, World!</h1>
    <p>This is my site.</p>
  </body>
</html>
```

If you want to know more about Pug, check out [my post](https://dev.to/jessewei/pug-a-html-templating-language-3oe2).

---


## How Tailwind CSS Works

Tailwind CSS is a utility-first CSS framework. It provides a set of pre-defined CSS classes that can be used directly in HTML markup without having to write any CSS code from scratch (mostly).

Let's say I want to give the `p` element in the following markup a font size of `20px` and a color of dark red, I can do,

```html
<p class="text-xl text-red-900">Hello World</p>
```

When compiled, Tailwind CSS adds the `text-xl` and `text-red-900` classes to the output stylesheet (the CSS file we link in the head of our HTML) where the CSS of the classes are specified:

```css
.text-xl {
  font-size: 1.25rem; /* 20px */
  line-height: 1.75rem; /* 28px */
}

.text-red-900 {
  color: rgb(124 45 18);
}
```

You can see it's no magic here. We're still using CSS to style our page, just that instead of defining the classes and writing the CSS ourselves, Tailwind CSS does the heavy lifting for us.

---


## Build and Deploy an Example in <10 Minutes

Now we've seen how Pug and Tailwind CSS work separately, it's time to put the pieces together. We'll build a sample page and this is how it looks like when finished:


![Sample page to build](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ign0yv59d68jb2ll6d5.png)

<figcaption>Sample page to build(Photo by <a href="https://unsplash.com/@marekpiwnicki?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Marek Piwnicki</a> on <a href="https://unsplash.com/photos/G_6kPyje9Lk?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>)</figcaption>

It's simple but looks good enough. More importantly, you can build it in less than 10 minutes without writing a single line of HTML or CSS!

### Get Started

Bootstrapping a project that uses Pug and Tailwind CSS for the first time can be a bit tricky, so I created an [npx tool](https://www.npmjs.com/package/create-pug-tailwindcss-app) to make your life easier.

To get started, just run the following command in your terminal (remember to replace your-project-name with your real project name):

```bash
npx create-pug-tailwindcss-app your-project-name
```

Now, your project structure should look like this:

```bash
.
├── README.md
├── bin
│   └── cli.js
├── images
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── index.pug
│   └── input.css
└── tailwind.config.js
```

You would work with,

- `src/`. This is where your Pug files and input CSS file (the CSS file to be compiled) reside.
- `images/`. This is where you put your images.
- `tailwind.config.js`. This is where you configure your Tailwind CSS or add global styles, if necessary.

You can ignore all the other directories and files in the project.

### Pug to HTML

Open the `src/index.pug` file and replace its content with the following:

```pug
//- 1. We can define variables in Pug just like we do in Javascript
- var navItems = ['Top', 'Services', 'About Us', 'Contact'] 

doctype html
html(lang='ja')
  head
    meta(name="viewport", content="width=device-width, initial-scale=1")
    title Foo Company
    link(rel="stylesheet" href="style.css")
  body
    header
      div
        a(href="#") Foo Company
        nav 
          ul
            //- 2. Iteration makes code more concise and readable
            each item in navItems
              li
                a(href="#")= item
    main
      section
        img(src="kv.jpg", alt="key visual of Foo Company")
        h1 Foo Company
      section
        h2 Our Services
        div
          div
            h3 Service 1
            p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi accumsan, sem et porttitor placerat, lacus risus molestie ligula, congue venenatis augue ante ac dui. Aliquam ipsum neque, tempus id magna eget, fringilla sollicitudin nunc. Phasellus non eros maximus, posuere elit in, vestibulum orci. Phasellus eget pellentesque ligula.
          div
            h3 Service 2
            p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi accumsan, sem et porttitor placerat, lacus risus molestie ligula, congue venenatis augue ante ac dui. Aliquam ipsum neque, tempus id magna eget, fringilla sollicitudin nunc. Phasellus non eros maximus, posuere elit in, vestibulum orci. Phasellus eget pellentesque ligula.
          div
            h3 Service 3
            p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi accumsan, sem et porttitor placerat, lacus risus molestie ligula, congue venenatis augue ante ac dui. Aliquam ipsum neque, tempus id magna eget, fringilla sollicitudin nunc. Phasellus non eros maximus, posuere elit in, vestibulum orci. Phasellus eget pellentesque ligula.
    footer
      div
        a(href="#") Foo Company 
        nav 
          ul
            each item in navItems
              li
                a(href="#")= item
      small Copyright © 2023 Foo Company
```

Some interesting points to be noted:

- At 1, we defined the items of our nav in an array _just like we'd normally do in Javascript_.
- At 2, we used `each` expression to iterate our `navItems` variable which made the code much more concise and readable.

Now download the key visual image [here](https://unsplash.com/photos/G_6kPyje9Lk), rename it as `kv.jpg` and put into the `images/` directory.

Then run this command in your terminal to compile our Pug file into HTML:

```bash
npm start
```

You should notice a `dist/` directory is generated automatically in our project root. Within it, there is the compiled `index.html` and `style.css` files along with our key visual image.

Start your editor's Live Server extension and in the opened browser, click the dist directory. Our page should be displayed and should look like this by this point:


![Sample page before CSS is applied](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hn4fm79dbvusol5md0nx.png)

<figcaption>Sample page before CSS is applied</figcaption>

### Add Tailwind CSS Classes

Now it's time to add Tailwind CSS classes to our markup to give our page a cool style. Due to the limit of the length of this tutorial, I cannot go through all the classes used to style our page. But as an example, let's give our `header` a light grey background color:

```pug
...
header.bg-slate-100
...
```

Save your changes and the background color of the `header` should be changed in real-time in the browser. You can find more about the default colors you can use out of the box [here](https://tailwindcss.com/docs/background-color#setting-the-background-color).

As you saw above, styling our page is as easy as attaching Tailwind CSS classes to Pug tags. Our final `src/index.pug` looks like this:

```pug
- var navItems = ['Top', 'Services', 'About Us', 'Contact'] 

doctype html
html(lang='ja')
  head
    meta(name="viewport", content="width=device-width, initial-scale=1")
    title Foo Company
    link(rel="stylesheet" href="style.css")
  body
    header.w-full.bg-slate-100.fixed.top-0.left-0.z-10
      .container.flex.justify-between.items-center
        a.font-bold(href="#") Foo Company
        nav 
          ul.flex.justify-end
            each item in navItems
              li
                a.block.p-4(href="#")= item
    main
      section.relative.mb-12
        img.w-full.h-screen.object-cover.brightness-50(src="kv.jpg", alt="key visual of Foo Company")
        h1(class="text-6xl font-bold text-white absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2") Foo Company
      section.container.mb-12
        h2.text-4xl.font-bold.mb-6 Our Services
        .grid.grid-cols-3.gap-12
          div
            h3.text-2xl.font-bold.mb-3 Service 1
            p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi accumsan, sem et porttitor placerat, lacus risus molestie ligula, congue venenatis augue ante ac dui. Aliquam ipsum neque, tempus id magna eget, fringilla sollicitudin nunc. Phasellus non eros maximus, posuere elit in, vestibulum orci. Phasellus eget pellentesque ligula.
          div
            h3.text-2xl.font-bold.mb-3 Service 2
            p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi accumsan, sem et porttitor placerat, lacus risus molestie ligula, congue venenatis augue ante ac dui. Aliquam ipsum neque, tempus id magna eget, fringilla sollicitudin nunc. Phasellus non eros maximus, posuere elit in, vestibulum orci. Phasellus eget pellentesque ligula.
          div
            h3.text-2xl.font-bold.mb-3 Service 3
            p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi accumsan, sem et porttitor placerat, lacus risus molestie ligula, congue venenatis augue ante ac dui. Aliquam ipsum neque, tempus id magna eget, fringilla sollicitudin nunc. Phasellus non eros maximus, posuere elit in, vestibulum orci. Phasellus eget pellentesque ligula.
    footer.w-full.bg-slate-900.text-white
      .container.flex.justify-between.items-center.mb-6
        a.font-bold(href="#") Foo Company 
        nav 
          ul.flex.justify-end
            each item in navItems
              li
                a.block.p-4(href="#")= item
      small.block.text-center Copyright © 2023 Foo Company
```

For the other classes I used in the page, check out [Tailwind CSS docs](https://tailwindcss.com/). Just hit `CMD + /` (Mac OS) or `Ctrl + /` (Windows) and type in the property you want style (e.g. text color). 

### Go to Production

To bring our page to production, just run:

```bash
npm run build:prod
```

The `dist/` directory is re-generated. The only difference of this version of `dist/` and the dev version is the `index.html` in the production `dist/` is minified.

Now you can pick your favorite hosting service and upload the generated HTML, CSS and image files to it to publish your page.

---

## Conclusion

It can sound daunting to build a website using multiple new technologies other than HTML and CSS. But as I showed you in this tutorial, with a bit of good tooling, we can create a modern page times faster with Pug and Tailwind CSS than with traditional HTML and CSS workflow.

The benefit of generating HTML and CSS dynamically doesn't stop here. When the codebase of your page is large, for example, it makes sense to _componentize_ your page. This involves creating reusable _partials_ and _mixins_ which [Pug](https://pugjs.org/language/mixins.html) supports out of the box. This way, when you want to make a change to a part which is used in multiple places across the page, you only have to make the change once to the relevant partial or mixin. This makes your code much more maintainable.

Also, by leveraging the functionality of Pug to pass data or data file to the compiler, you can separate the data and UI layer of your code, which makes it far easier to generate versions of the same page in different languages, for example.