Pug.js Basics
pugjs.org

Pug.js Basics

Pug (formerly known as Jade) is a template engine that allows you to dynamically manipulate the HTML and CSS that are ultimately rendered from the files that were written in it. If the idea of a template engine sounds intimidating (or you've tried to use one before and found yourself frustrated), there's no need to worry-- As long as you have a solid understanding of HTML, you'll be able to pick-up on the basics of Pug pretty quickly. Pug can also be used to render a few other types of files (e.g., XML), but this tutorial will focus on HTML.

By the way, to reinforce your learning here (or if video is just more your style), I'd suggest checking out Pug Template Engine - Full Tutorial for Beginners by dcode on the FreeCodeCamp YouTube channel.

Prerequisites:

  • Solid understanding of HTML
  • Basic understanding of CSS
  • Basic understanding of JavaScript
  • Node.js installed on your computer (so you can use NPM)
  • An IDE with an integrated terminal, like Visual Studio Code

Sections:

  • Getting Started
  • General Syntax
  • Classes and Ids
  • Attributes
  • Adding JS Code
  • CSS Styling
  • Looping
  • Conditionals
  • Case statements
  • Includes
  • Mixins (functions)
section divider

Getting Started with Pug

1. In your project folder, create a folder called html.

2. Install the Pug CLI package from Node Package Manager (NPM) by running the following command.

  • Tip: Remove the -g flag in the command if you don't want to install Pug globally.
npm install pug-cli -g

3. In the root directory, create a file called index.pug (you may also see this named app.pug in some projects.)

4. In the terminal, issue the following command to set-up automatic tracking for updates files and to send your converted .pug files to the .html to be rendered at runtime.

  • This command translates to "watch for changes (-w) from the root directory onware (./), send the output (-o) of the .pug files to the html folder (./html) and pretty=print (-P) them."
pug -w ./ -o ./html -P


section divider

General Pug Syntax

Pug syntax uses non-bracketed element tags that are similar to their HTML counterparts.

Pug:

doctype html

Rendered HTML:

<!DOCTYPE html>

  • Note: Even if the file format you're rendering to doesn't necessarily require you to explicitly state the doctype, declare it so Pug knows what file type you want.

Pug will automatically generate a closing tag for elements that require one, so you only have to write the opening tag. This is because Pug uses formatting elements (such as white space and indentation) to determine parent/child relationships between elements.

Pug:

html

Rendered HTML:

<html></html>

To create a child element, indent the line under the intended parent and create the child there. In this example, the head element is on an indented line underneath the html element, which renders it as a child of the html element.

Pug:

doctype

html
  head
  

Rendered HTML:

<!DOCTYPE html>

<html>
  <head></head>
</html>

To put content inside an element, put a space after its tag name (on the same line) and add the content there.

Pug:

h1 This is my heading

Rendered HTML:

<h1>This is my heading</h1>

To add multiple lines of content inside an element, put a period after the element's name and drop the content below, indenting each line.

Pug:

// Correct syntax for multi-line content

p.
  This is line 1 of this paragraph.
  This is line 2 of this paragraph.
  This is line 3 of this paragraph.
   

Rendered HTML:

<!-- Correct syntax for multi-line content -->

<p>
  This is line 1 of this paragraph.
  This is line 2 of this paragraph.
  This is line 3 of this paragraph.
</p>
  

If you don't use this syntax for multi-line content, Pug will interpret the lines underneath the element as separate elements. In this example, Pug renders the p element as intended, but also renders the word "This" in the subline as an element of type This.

Pug:

// Incorrect syntax for multi-line content

p This is line 1 of this paragraph.
  This is line 2 of this paragraph.
 

Rendered HTML:

<!-- Incorrect syntax for multi-line content -->

<p>This is line 1 of this paragraph.</p>
  <This>is line 2 of this paragraph.</This>
 


section divider

Classes and Ids in Pug

Pug syntax uses CSS selectors to denote elements' classes and ids.

To add an id to an element, append its tag with a hashtag (#) and the desired id.

To add a class to an element, append its tag with a period (.) and the desired class.

Any id or class in the file that isn't attached to an element will be rendered as a div.

Pug:

h1#main-header Real Fake Doors
 
p.greeting Hey! Are you tired of real doors cluttering up your house?

.call-to-action Get on down to Real Fake Doors!

Rendered HTML:

<h1 id="main-header">Real Fake Doors</h1>

<p class="greeting">Hey! Are you tired of real doors cluttering up your house?</p>

<div class="call-to-action">Get on down to Real Fake Doors!</div>


section divider

Other Attributes in Pug

To add attributes other than ids and classes to Pug, append parentheses to the element tag, and put their attributes and values inside them. Just like in HTML, multiple attributes can be separated with spaces.

Pug:

input(type="password" name="userpwd")

Rendered HTML:

<input type="password" name="userpwd">

We will discuss how to add a collection of attributes to an element and how to add attributes with conditional data in the section below, Adding JavaScript Code to Pug.

section divider

Adding JavaScript Code to Pug

To add a line of JavaScript to your pug file, start the line with a dash (-) and write your JS code after it.

For example, as mentioned in the previous section, you can use JavaScript to create a collection of attributes which you can then apply to a given element. The syntax for this is to append &attributes to the element tag, followed by the name of the collection in parentheses.

Pug:

- const felineAttibutes = { "src": "cat-pic.png", "alt": "maine coon cat" }


img&attributes(felineAttributes)

Rendered HTML:

<img src="cat-pic.png" alt="maine coon cat">

Another example mentioned in the previous section is adding conditional values to an element's attributes using JavaScript. The code below uses a ternary operator to determine which of the values to use based on the given condition.

Pug:

// Since the condition (3 > 2) is true, the first value is used

input(data-js=`${ 3 > 2 ? "OK" : "NOT OK" }`)


// Since the condition (3 < 2) is false, the second value is used

input(data-js=`${ 3 < 2 ? "OK" : "NOT OK" }`)

Rendered HTML:

<!-- Since the condition (3 > 2) is true, the first value is used -->

<input data-js="OK">


<!-- Since the condition (3 < 2) is false, the second value is used-->

<input data-js="NOT OK">


section divider

CSS Styling in Pug


Inline CSS

You can add the style attribute to an element using the same syntax you would with any other element. Likewise, you can also create a JavaScript collection of such values to apply.

Pug:

div(style="color: aqua; background-color: blue;"


- const divColors = { "color": "mint", "background-color": "darkturquoise" }

div(style=divColors)

Rendered HTML:

<div style="color: aqua; background-color: blue;"></div>

<div style="color: mint; background-color: darkturquoise"></div>


Internal CSS

To write internal CSS in Pug, use the multi-line syntax for the style element, putting each style rule on its own indented line beneath it.

Pug:

style.
  p {
    color: green;
    background-color: black;
  }
  div {
    border: 1px solid purple;
  } 

Rendered HTML:

<style>
  p {
    color: green;
    background-color: black;
  }
  div {
    border: 1px solid purple;
  }
</style>
                  


External CSS

To link an external CSS file in your Pug file, use the same syntax you would for any other element and its associated attributes and apply it to the link element.

Pug:

link(rel="stylesheet" href="styles.css")

Rendered HTML:

<link rel="stylesheet" href="styles.css">


section divider

Looping in Pug

The each and for loops have the same functionality in Pug, so these keywords are largely interchangeable; accordingly, in the following examples, I will use the each keyword, but you can sub-in the for keyword and get the same results.

The basic syntax for a loop declaration is the keyword each, followed by a temporary variable name that will hold each item in the collection as it is iterated over, followed by the keyword in, and finally, the collection to be iterated over.

Inside the body of the loop, you will append an equal sign (=) to an element that contains a variable from the loop, so that it will be interpreted as its value, rather than just a string (i.e., its name). This syntax means that the whole line is read as an expression, so you will need to use typical concatenation and other means to put it together.

Pug:

each num in [1, 2, 3]
  p= "number = " + num
 

Rendered HTML:

<p>number = 1</p>
<p>number = 2</p>
<p>number = 3</p>

To pull the index of each item in the iteration, add a name for the index (this can be anything, but will be represented by i in this example) after the temporary variable for the iteration item (in this example, num).

Pug:

each num, i in [10, 20, 30, 40, 50]
  p= num + " [" + i + "]"

Rendered HTML:

<p>10 [0]</p>
<p>20 [1]</p>
<p>30 [2]</p>
<p>40 [3]</p>
<p>50 [4]</p>

Since this is looping over collections, a JavaScript object can be substituted in place of a hard-coded array.

Pug:

// looping through a JS array

- const puppies = ["Millie", "Dottie", "Jill", "Captain", "Marco"]


each pup, i in puppies
  p= pup + " [" + i + "]"


// looping over a JS object

- const kittens = {"Frazier": "male", "Pepe": "male", "Milo": "male", "Cookie": "female", "Tilly": "female"}

each kit, i in kittens
  p= i + " - " + kit
  

Rendered HTML:

<!-- looping through a JS array -->

<p>Millie [0]</p>
<p>Dottie [1]</p>
<p>Jill [2]</p>
<p>Captain [3]</p>
<p>Marco [4]</p>

<!-- looping over a JS object -->

<p>Frazier - male</p>
<p>Pepe - male</p>
<p>Milo - male</p>
<p>Cookie - female</p>
<p>Tilly - female</p>

When creating loops, you can also specify an else condition to be run if the code finds that the collection it's supposed to iterate over is empty.

Pug:

h1 Adoption Day - Lizards

- const lizards = []

each liz in lizards
  p= liz
else
  p Sorry! There are no lizards up for adoption at this time.

Rendered HTML:

<h1>Adoption Day - Lizards</h1>

<p>Sorry! There are no lizards up for adoption at this time.</p>


section divider

Conditionals in Pug

To make conditional statements in Pug, you can use the typical if, else if, and else keywords.

These examples will show another type of syntax used to create plain text content without the first word being interpreted as an HTML tag; to accomplish this, we'll start the line with a pipe (|). The examples will also demonstrate how to use JavaScript values in the HTML via expression syntax ( ${ } ).

Pug (if):

// if logic displaying HTML based on a user status


- let user1 = { name: "Kyra", loggedin: true, lastActive: 65, admin: false }

if user.loggedIn
  p
    | Welcome back,
    strong #{ user.name }

Rendered HTML (if):

<!-- if logic displaying HTML based on user status -->

<p>Welcome back, <strong>Kyra<strong></p>


Pug (else if):

- let user2 = { name: "Filipe", loggedin: false, admin: false }

if user.loggedIn
  p
    
    | Welcome back,
    strong ${ user.name}
  
// else if logic displaying HTML based on status for non-admin accounts

else if user.admin = false
  p
    a(href="/login") Log In            
                  

Rendered HTML (else if):

<!-- else if logic displaying HTML based on status for non-admin accounts -->

<p>
  <a href="/login">Log In</a>
</p>
  


Pug (else):

- let user3 = { name: "Delaney", loggedin: false, admin: true }

if user.loggedIn
  p
    
    | Welcome back,
    strong ${ user.name}
  
else if user.admin = false
  p
    a(href="/login") Log In 

// else logic displaying HTML based on last login for admin accounts

else
  p
    a(href="/login") Log In As User
  p
    a(href="/admin") Log In As Admin


Rendered HTML (else):

<!-- else logic displaying HTML based on last login for admin accounts -->

<p>
  <a href="/login">Log In As User</a>
</p>
<p>
  <a href="/admin">Log In As Admin</a>
</p> 


section divider

Case Statements in Pug

Case statements in Pug are essentially JavaScript switch statements.

The declaration syntax involves the case keyword followed by the value to compare against. After that, there are the conditions for the switch, which use the when keyword for each specific criterion and the default keyword for what to do when no case is matched.

Pug:

h1 Application Status

- const applicationStatus = "received"

case applicationStatus
  when "received"
    p Your application has been received but has not yet been reviewed.
  when "in review"
    p Your application is currently in review. We will be in touch soon.
  when "accepted"
    p Congratulations! Your application has been accepted!
  when "rejected"
    p We've decided to move forward with other applicants at this time.
  default
    p Either your application didn't make it to our system, or there was an error.
     

Rendered HTML:

<h1>Application Status</h1>

<p>Your application has been received but has not yet been reviewed.</p>


section divider

Includes in Pug

The include keyword allows you to import Pug files into other Pug files (for example, if you wish to have a header file that is imported into all the files representing different pages on a website).

Use the keyword followed by the relative path of the Pug file you wish to include. Note that you don't need to specify the .pug extension, because Pug will assume that for you.

Pug:

body

  // site header
  include sharedAssets/headerNav
  
  h1 About Us
  p The Mystery Shack is a tourist trap located in Gravity Falls, Oregon.
  
  // site footer
  include sharedAssets/footerNav
          

Rendered HTML:

<body>
  
  <!-- site header -->
  <ul>
    <li>Home</li>
    <li>About Us</li>
    <li>Contact us</li>
  <ul>

  <h1>About Us</h1>
  <p>The Mystery Shack is a tourist trap located in Gravity Falls, Oregon.</p>

  <!-- site footer -->
  <ul>
    <li>(c) Pines, Inc. 2012</li>
    <li>Site Map</li>
  </ul>
       


section divider

Pug Mixins

A mixin is a reusable block of code that behaves like a JavaScript function (i.e., they can be called, take data in as arguments, and etc.)

The declaration for a mixin should be written at the top of the Pug file. You can use all of the syntax already discussed in this article (e.g., for structuring HTML, handling data, and so forth) to format the mixin like a JS function.

To call a mixin, use a plus sign (+) with the mixin's name and parameters (if any) appended to it.

Pug:

mixin generateComment(commentData)
  
    .comment
    
    if commentData.postedByAdmin
          strong Admin
    
    em.author = commentData.author
    p.text = commentData.text 

doctype html
html
  head
    title Comments Page
  body
    - const userComment1 = { author: "TheMightyMonarch", admin: true, text: "Hi" }
    +generateComment(userComment1)

    - const userComment2 = { author: "Henchman21", admin: false, text: "Hello" }
    +generateComment(userComment2)

Rendered HTML:

<!DOCTYPE html>
<html>
  <head>
     <title>Comments Page</title>
  </head>
  <body>
     <div class="comment">
        <strong>Admin</strong>
        <em class="author">TheMightyMonarch</em>
        <p class="text">Hi</p>

     <div class="comment">
         <em class="author">Henchman21</em>
         <p class="text">Hello</p>
   </body>
</html>
 
Munendra Gaur

Java Developer @ Aventra Group || Former SDE Intern @Global Logic || 1600+ Rating on leetcode

3 个月

?///a(href=link)(style="color: white;") is this the wrong way to place a link Sondra Coffin

回复
Albin Eugen Trotter Echeverría

Master of Engineering Management

1 年

Thank you for this article, it's great to have it for reference!

回复
Asif Suhail Khan

? Structural Design Engineer

1 年

easy to understand , thanks . ??

要查看或添加评论,请登录

Sondra Coffin的更多文章

  • Welcome to the Wonderful World of HTML

    Welcome to the Wonderful World of HTML

    HTML is a computing language that is used to “tell” computers how a web page should be structured. It is a fundamental…

  • Use the Visual Studio Code "Prophet Debugger" extension to connect to a Salesforce Commerce Cloud sandbox

    Use the Visual Studio Code "Prophet Debugger" extension to connect to a Salesforce Commerce Cloud sandbox

    I just finished working my way through a Medium article by Manu Saini regarding connecting VSCode (Visual Studio Code)…

    1 条评论
  • 10 Minute Vue App

    10 Minute Vue App

    The Intro Vue is a front-end JavaScript framework that packs a lot of the same features of other popular frameworks…

  • Getting Started with Asynchronous JavaScript

    Getting Started with Asynchronous JavaScript

    When I'm trying to learn something new and am finding trouble wrapping my head around the overarching concept, my first…

  • Git Refresher

    Git Refresher

    * * * PLEASE NOTE * * * ?As of June 2020, GitHub now refers to the "master" branch as the "main" branch by default…

  • Quick Tip: Shortcut a query in Oracle SQL Developer or SQL Server Management Studio

    Quick Tip: Shortcut a query in Oracle SQL Developer or SQL Server Management Studio

    After going back and forth copy-and-pasting or trying to remember queries for my current project, I decided wanted to…

  • My Journey into SOAP

    My Journey into SOAP

    Introduction This article embodies my understanding of SOAP-- which is admittedly simplified in some areas-- in the…

    2 条评论
  • 3 Quick Tips for Absolute Beginner Coders

    3 Quick Tips for Absolute Beginner Coders

    I've gotten a lot of messages from people across the world asking about my journey into code, so I wanted to take a few…

    2 条评论
  • Why You Should Hire a Candidate with Teaching Experience

    Why You Should Hire a Candidate with Teaching Experience

    Having been an educator for several years, I know firsthand how valuable teachers' knowledge, skills, and work ethic…

    6 条评论
  • A Teacher's To-Do List

    A Teacher's To-Do List

    I recently wrote an article for staffing managers on Why You Should Hire a Candidate with Teaching Experience, and…

    2 条评论

社区洞察

其他会员也浏览了