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)
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
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>
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>
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.
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">
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">
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>
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>
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>
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>
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>
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
Master of Engineering Management
1 年Thank you for this article, it's great to have it for reference!
? Structural Design Engineer
1 年easy to understand , thanks . ??