DEV Community

Cover image for Type less! Use Pug Templates!
Johnny Fekete
Johnny Fekete

Posted on

Type less! Use Pug Templates!

While I was working on the 24 CSS artworks for my CSS Christmas Calendar I quickly realized that I would have to write <div> and </div> a million times.

Besides being very monotone, it is also extremely error-prone. It's so easy to forget closing a div, or other elements.

I wanted to save myself from a lot of unnecessary keystrokes and headaches.
That's why I decided to give Pug - a HTML templating engine -
a try.

What Is Pug?

Pug in yellow jacket

Photo by Charles Deluvio on Unsplash

Pug.js is a HTML templating engine, which translates pug code to HTML tags.

It requires some configuration in your backend, so it gets compiled. But luckily, it's easy to get started on Codepen without any local setup.

Just create a new pen, go to the settings, and enable the Pug templating engine.

Enable Pug templating engine on Codepen

So how to write pug templates?

Here's a simple example:

.hot-chocolate
  .mug
    .mug__grip
    .mug__contents
Enter fullscreen mode Exit fullscreen mode
Code from the Hot chocolate with marshmallows CSS art

that compiles to

<div class="hot-chocolate">
  <div class="mug">
    <div class="mug__grip"></div>
    <div class="mug__contents"></div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Let's highlight some important things here:

  • indentation is everything! if you start the next line under the previous, it will be a sibling HTML element. But if you press a TAB, it will be the children of it.
  • no need for closing tags. The proper indentation will take care of them automatically.
  • use your existing CSS knowledge: if something starts with a ., it will be a class. # stands for id.

Easy Peasy. Something More Complex?

So far we only worked with empty divs.

But you can add content to them:

.title Santa Claus
.description.
  a plump, white-bearded, red-suited, and jolly old man
  in modern folklore who delivers presents to 
  children at Christmastime
Enter fullscreen mode Exit fullscreen mode

As you could see, multiline content needs to be indented one level, and the element definition needs a . at the end.

Changing the tag from div is just as simple:

a.link I'm a link
span.highlight I'm a highlighted text
footer I don't even have a class
Enter fullscreen mode Exit fullscreen mode

Finally, you can edit the elements attributes the following way:

input(type='text' name='address' autofocus)
a(href='https://csschristmascalendar.com' target='_blank')
Enter fullscreen mode Exit fullscreen mode

Mixing Pug with JavaScript

As I mentioned, Pug is a templating engine written in JavaScript.
Therefore, you can combine it with any Javascript code, and that's where it's superpower begins.

- let authenticated = false;

.login(class=authenticated ? 'hidden' : 'visible')
Enter fullscreen mode Exit fullscreen mode

Here the class changed based on a JavaScript variable. Notice, how class is used as an attribute, and not in the selector.

Also, the plain JavaScript line starts with a dash - to mark that it's not a template

- let length = 10;

ul.items(style=`height: ${Math.min(length * 2, 10)}rem`)
Enter fullscreen mode Exit fullscreen mode

Here the height will be a maximum of 10rem.

Finally, one thing I found quite useful is combining pug with the random() function:

.star(style=`transform: rotate(${Math.random() * 360}deg)`)
Enter fullscreen mode Exit fullscreen mode

This will set a random rotate transform on the div.

Conditional Rendering

One of the cool things in Pug is that it can conditionally render elements.

Here's an example:

- let authenticated = false;

.header
  if (authenticated)
    a(href='/logout') Sign out
  else
    a(href='/login') Sign in
Enter fullscreen mode Exit fullscreen mode

This example will render either the Sign in or Sign out button, depending on the authenticated variable.

Loops That Will Save Your Time

If you have to render the same block of code multiple times, loops will save you from unnecessary repetition.

Let's start with a simple case, looping through an array of items:

- const menuItems = ['intro', 'about', 'portfolio', 'contact'];

ul
  each menuItem in menuItems
    li
      a(href=`#${menuItem}`)= menuItem
Enter fullscreen mode Exit fullscreen mode

This will compile to:

<ul>
  <li><a href="#intro">intro</a></li>
  <li><a href="#about">about</a></li>
  <li><a href="#portfolio">portfolio</a></li>
  <li><a href="#contact">contact</a></li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Notice, how I added an equal character = after the <a> tag. That to tell Pug that what comes after is a JavaScript variable, so it doesn't print the word menuItem for each link.

For loop is another one that I used heavily in the CSS arts. It repeats the same content n times.

It's important to note that for is not a Pug technique, but plain JavaScript. However, that's the beauty of it all: you can combine the two, without any problems:

.sky
  - for (var i = 1; i <= 10; i++)
    .star
Enter fullscreen mode Exit fullscreen mode

This will create 10 <div class="star"></div> elements inside the sky

.

I used this trick in almost all items, often combined with more complex parameters:

.sparkler-light
  - for (var spark = 1; spark <= 36; spark++)
    .spark(
      class=`spark-${spark}`
      style=`--spark-rotate: ${spark * 10}deg;
        --spark-delay: ${Math.round(Math.random() * 1000)}ms`
    )
Code from the Animated Christmas Sparkler CSS art

This creates the following HTML

<div class="sparkler-light">
  <div class="spark spark-1" style="--spark-rotate: 10deg;
    --spark-delay: 359ms"></div>
  <div class="spark spark-2" style="--spark-rotate: 20deg;
    --spark-delay: 887ms"></div>

  ...

  <div class="spark spark-36" style="--spark-rotate: 360deg;
    --spark-delay: 121ms"></div>
</div>

With the for loop I could add 36 sparks rotated by 10 degrees each, and with a random delay in their animation, that - combined with CSS - resulted in this:

Christmas Sparkler made with CSS

Animated Christmas Sparkler

Sounds Cool! What's Next?

Now you are ready to enable your Pug templating engine!

You can make more use of it by including other pug files, creating complex layouts, or even including markdown files.

Adding Pug to your projects is very easy, just follow the official documentation. It has very straightforward steps about the setup and integration.

If you just want to manually convert a Pug template to HTML, I found this online converter that did an amazing job for me, and it will certainly make it for you too.

Finally, if you need a quick overview of the most common Pug syntaxes, check this cheat sheet.
You can come back to it anytime you need a specific syntax, especially for the more complex elements.

I'd love to hear from you, and see how you implemented Pug in your projects.

Leave a comment below, and I'd be glad to answer your questions and comments.

Top comments (2)

Collapse
 
robertseidler profile image
RobertSeidler

I just created my first project using pug (as view-renderer in express) last week. And I think u hit the nail on the head in your introduction. Writing html can be tiring and also is confusing / uneasy to read.

Pug is really clear and is written super fast. Initially I chose it for reusing templates in other templates (like header and footer), but I fell in love immediatly. <3

I still need to check the cheat sheet every now and again, but I already feel like I absorbed everything necassary to build the templates I want.

Collapse
 
johnnyfekete profile image
Johnny Fekete

Yes, I felt the same.
The learning curve is really quick for basic use cases, and I could just quickly check the cheat sheet whenever I needed something more complex.

I don't know how old this whole Pug.js is, or how widespread (honestly I didn't hear about it until a month ago) but it's really efficient so people should go and use it