Pug (formerly known as Jade) is a preprocessor which simplifies the task of writing HTML. It also adds a ton of functionality, such as JavaScript objects, conditionals, loops, mixins and templates. The syntax is arguably a lot cleaner to read and it can be a real time-saver when working with a lot of HTML (especially frameworks such as Bootstrap, Foundation, etc).

Lets take a peek at some Pug syntax & compare it to regular HTML..

// index.pug
doctype html  
html(lang='en')  
 head
   title Pug demo
 body
   h1 Welcome to Pug Life
   div.container
     p I'm a p that needs to be contained!

Note the use of indentation to nest our HTML as we require. And the lack of closing tags!

And hereā€™s the standard HTML output:

<!-- index.html -->

<!DOCTYPE html>  
<html lang="en">  
 <head>
   <title>Pug demo</title>
 </head>
 <body>
   <h1>Welcome to Pug Life</h1>
   <div class="container">
     <p>I'm a p that needs to be contained!</p>
   </div>
 </body>
</html>

By comparison our pug code is much more concise. Additionally, the compiler will throw errors if we have any mistakes in our code ā€“ which makes for convenient error prevention.

So letā€™s get started!

How to Install Pug

Note: Youā€™ll need NodeJS installed! Go ahead and install if you havenā€™t already.

To install pug run the following command from your terminal:

npm install -g pug-cli

We install globally with -g as weā€™ll need access to Pug commands from terminal.

Now in our root directory, create a file called index.pug.

Let's test this out! Add the following text to our file as follows:

// file: index.pug

doctype html

And lets compile it to HTML with the following command:

pug index.pug

We should now see our index.html generated in the root directory. It will of course convert to HTML as follows:

// file: index.html

<!DOCTYPE html>

When working on a larger project, you might want to use a more specific compile command, such as:

pug -w ./ -o ./html -P

The -w flag will watch our pug file for changes and re-compile automatically each time we save. ./ will watch everything in the current directory. -o ./html will set the output folder to html. -P will make our HTML source code pretty printed, with indentation, line-breaks, etc.

Note: Once youā€™ve executed this command, keep your terminal running to continue the auto-compile!

The Basics

Let's get started on a basic HTML structure. Type up the following in your index.pug.

doctype html
html
  head
  body
    h1#title Lets get pugging!
    p I'm a paragraph
    p.
      I'm a multi-line paragraph!
      And this is the second line.
    p.para. 
      This paragraph has class!
    .firstDiv A div with a class.
    #secondDiv A div with an id.

Note the use of indentation! Make sure you tab your child elements.

When you save and open up index.html. Youā€™ll see the complete HTML generated like so..

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <h1 id="title">Lets get pugging!</h1>
    <p>I'm a paragraph</p>
    <p>
      I'm a multi-line paragraph!
      And this is the second line.
    </p>
    <p class="para">This paragraph has class!</p>
    <div class="firstDiv">A div with a class.</div>       
    <div id="secondDiv">A div with an id.</div>
  </body>
</html>

Attributes

Let's take a look some syntax for setting attributes in pug.

doctype html
html
  head
    //- Invisible comment.
    //Visible comment.    
    script(src="script.js")
    link(rel='stylesheet', href='css/main.css')
  body
    a(href="https://google.com") google.com
    img(src="https://google.com/logo.png" alt="google logo")
    input(type="password" name ="inputpass")
    input(type='checkbox' checked)
    input(type='checkbox' checked=true)
    input(type='checkbox' checked=false)
    //Inline styles
    a(href="your-link", style={color: "Red", "font-size": "24px"}) I'm a link!

Our HTML will generate as follows:

<!DOCTYPE html>
<html>
  <head>
    <!--Visible comment.-->
    <script src="script.js"></script>
    <link rel="stylesheet" href="css/main.css">
  </head>
  <body>
    <a href="https://google.com">google.com</a>
    <img src="https://google.com/logo.png" alt="google logo">
    
    <input type="password" name="inputpass">
    <input type="checkbox" checked>
    <input type="checkbox" checked>
    <input type="checkbox">
    <!--Inline styles-->
    <a href="your-link" style="color:Red;font-size:24px;">I'm a  link!</a>
  </body>
</html>

Adding JavaScript

One of the most powerful features of Pug, is the ability to easily make our HTML dynamic, using inline JavaScript. Lets take a look at a few examples:

Variables

- let name = 'Timothy'
- let city = 'Montreal'
- let transport = { type: 'Bike' }
- let food = ['Tacos', 'Pizza', 'Cheetos']

// Incrementation for numeric variables
age++

// Assigning variables to elements
p= name
span.age= age

Interpolation

- let size ="medium"
  img(src=`https://google.com/logo-${size}.png` alt="logo")
---------------------

// output:
<img src="https://google.com/logo-medium.png" alt="logo">

Loops

ul
  each city in ['Sydney', 'Montreal', 'New York']
    li= city
ul
  each city, index in ['Sydney', 'Montreal', 'New York']
    li= 'Number ' + index + ': ' + city
-------------------------------------------------
// output:
<ul>
  <li>Sydney</li>
  <li>Montreal</li>
  <li>New York</li>
</ul>
<ul>
  <li>Number 0: Sydney</li>
  <li>Number 1: Montreal</li>
  <li>Number 2: New York</li>
</ul>

Conditionals

if user
  h2 Welcome back #{user}!
else if admin
  h2 Hey #{admin}!
else
  h2 Sign up!

Mixins

// Declaration
mixin list
  ul
    li Sydney
    li Montreal
    li New York
// Use
+list
+list
------------------
// output:
<ul>
  <li>Sydney</li>
  <li>Montreal</li>
  <li>New York</li>
</ul>
<ul>
  <li>Sydney</li>
  <li>Montreal</li>
  <li>New York</li>
</ul>

Mixins compile as functions, and therefore can take arguments!

mixin city(name)
  li.city= name
ul
  +city('Sydney')
  +city('Montreal')
  +city('New York')
--------------------
// output:
<ul>
  <li class="city">Sydney</li> 
  <li class="city">Montreal</li>
  <li class="city">New York</li>
</ul>

The features weā€™ve looked at here are really just the tip of the iceberg! For the full specs check out PugJS.org ā€” Getting Started.

Structuring your Pug files

A well organized template system is a crucial part of any development process. What follows is a look at how we can organize our projects using both includes and extends.

Includes

Includes allow you to insert the contents of one Pug file into another. All you need to do is add an include directive into your main pug file, as follows:

doctype html
html
  include additions.pug
  body
    h1 My Heading
    p Here goes the text.

Lets now create the additions.pug file and add the following content:

head
  title My Site
  script(src='/js/jquery.js')
  script(src='/js/app.js')

Our files will compile merged into index.html like so:

<!DOCTYPE html>
<html>
  <head>
  <title>My Site</title>
  <script src="/js/jquery.js"></script>
  <script src="/js/app.js"></script>
  </head>
  <body>
    <h1>My Heading</h1>
    <p>Here goes the text.</p>
  </body>
</html>

Extends

The extends keyword allows a template to extend a layout or parent template. It can then override certain pre-defined blocks of content, using the block command.

We want to keep our projects as organized as possible! A logical template system will define a base template, and then all the other templates extend from it. For example:

// file: index.pug

extends layout.pug

block content
  h1 hello world!

Here weā€™ve set our index.pug file as the base template. With a call to the layout.pug file via extends.

Note the use of the block command. This is how we direct part of a template to be extended.

// file: layout.pug

doctype html
html(lang="en")
  head
    meta(charset='utf-8')
  body
    block content
    h2 hello again world!

Here is the content of our layout.pug, we use the block command with the same name (you can call it whatever you like!), so the pug engine knows where to put the code block.

This code will compile as follows:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>hello world!</h1>
    <h2>hello again world!</h2>
  </body>
</html>

Of course you can use as many blocks as you like, and create as many pug files as you like. The point is to build a logical structure into our projects & keep our code clean and organized!

Wrapping up

And thatā€™s it! Weā€™ve setup a Pug development environment and covered the fundamentals. Weā€™ve looked at many of the features provided by adding JavaScript such as variables, interpolation, loops, conditionals and mixins. Weā€™ve also looked at how to structure our Pug files using templating with the include and extend directives.

Related Posts:


Tim profile image

A little about me..

Hey, Iā€™m Tim! šŸ‘‹

Iā€™m a freelance business owner, web developer & author. I teach both new and experienced freelancers how to build a sustainable and successful freelancing business. Check out myĀ Complete Guide to Freelancing if you'd like to find out more.

While you're here, you can browse through my blogs where I post freelancing tips, code tutorials, design inspiration, useful tools & resources, and much more! You can also join the newsletter, or find me on X.

Thanks for reading! šŸŽ‰