HTML & CSS
Article

A Jade Tutorial for Beginners

By Sanjay Guruprasad

Jade is an elegant templating engine, primarily used for server-side templating in NodeJS. In plain words, Jade gives you a powerful new way to write markup, with a number of advantages over plain HTML.

For example, take a look at this movie card in HTML:

<div>
  <h1>Ocean's Eleven</h1>
  <ul>
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
  <p>Danny Ocean and his eleven accomplices plan to rob
     three Las Vegas casinos simultaneously.</p>
</div>

This is what the same markup looks like in Jade:

div
  h1 Ocean's Eleven
  ul
    li Comedy
    li Thriller
  p.
    Danny Ocean and his eleven accomplices plan to rob
    three Las Vegas casinos simultaneously.

The Jade version is elegant and concise. But it’s not just about the beautiful syntax. Jade has some really neat features, allowing you to write modular and reusable markup. Before we get into these powerful features, let’s do a quick overview of the basics.

More from this author

The Basics

I’m going to highlight three basic features in Jade

  • Simple tags
  • Adding attributes to the tags
  • Blocks of text

If you want to try this out as we go along, you can use CodePen and choose Jade as your HTML preprocessor or use the online compiler on the official Jade page to compile your Jade to HTML.

Simple Tags

As you might have noticed earlier, there are no “closing” tags in Jade. Instead, Jade uses indentation (i.e. white space) to determine how tags are nested.

div
  p Hello!
  p World!

In the example above, since the paragraph tags are indented, they will end up inside the div tag. Simple!

<div>
  <p>Hello!</p>
  <p>World!</p>
</div>

Jade compiles this accurately by treating the first word on each line as a tag, while subsequent words on that line are treated as text inside the tag.

View this example on CodePen

Attributes

All this is great, but how do we add attributes to our tags? Quite simple really. Let’s go back to our first example and toss in some classes and a poster image.

div(class="movie-card", id="oceans-11")
  h1(class="movie-title") Ocean's 11
  img(src="/img/oceans-11.png", class="movie-poster")
  ul(class="genre-list")
    li Comedy
    li Thriller

Pretty neat right?

<div class="movie-card" id="oceans-11">
  <h1 class="movie-title">Ocean's 11</h1>
  <img src="/img/oceans-11.png" class="movie-poster">
  <ul class="genre-list">
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
</div>

View this example on CodePen

But it doesn’t stop here. Jade provides special shorthand for IDs and classes, further simplifying our markup using a familiar notation:

div.movie-card#oceans-11
  h1.movie-title Ocean's 11
  img.movie-poster(src="/img/oceans-11.png")
  ul.genre-list
    li Comedy
    li Thriller

View this example on CodePen

As you can see, Jade uses the same syntax as that which we’re already familiar with when writing CSS selectors, making it even easier to spot classes.

Blocks of Text

Let’s say you have a paragraph tag and you want to place a large block of text in it. Jade treats the first word of every line as an HTML tag – so what do you do?

You might have noticed an innocent period in the first code example in this article. Adding a period (full stop) after your tag indicates that everything inside that tag is text and Jade stops treating the first word on each line as an HTML tag.

div
  p How are you?
  p.
    I'm fine thank you.
    And you? I heard you fell into a lake?
    That's rather unfortunate. I hate it when my shoes get wet.

View this example on CodePen

And just to drive home the point, if I were to remove the period after the p tag in this example, the compiled HTML would treat the “I” in the word “I’m” as an opening tag (in this case, it would be the <i> tag).

Powerful Features

Now that we’ve covered the basics, let’s take a peek at some powerful features that will make your markup smarter. We’ll look at the following features in remainder of this tutorial:

  • Loops
  • JavaScript
  • Interpolation
  • Mixins

Using JavaScript in Jade

Jade is implemented with JavaScript, so it’s super-easy to use JavaScript in Jade. Here’s an example.

- var x = 5;
div
  ul
    - for (var i=1; i<=x; i++) {
      li Hello
    - }

What did we just do here?! By starting a line with a hyphen, we indicate to the Jade compiler that we want to start using JavaScript and it just works as we would expect. Here’s what you get when you compile the Jade code above to HTML:

<div>
  <ul>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
  </ul>
</div>

View this example on CodePen

We use a hyphen when the code doesn’t directly add output. If we want to use JavaScript to output something in Jade, we use =. Let’s tweak the code above to show a serial number.

- var x = 5;
div
  ul
    - for (var i=1; i<=x; i++) {
      li= i + ". Hello"
    - }

And voilà, we now have serial numbers:

<div>
  <ul>
    <li>1. Hello</li>
    <li>2. Hello</li>
    <li>3. Hello</li>
    <li>4. Hello</li>
    <li>5. Hello</li>
  </ul>
</div>

View this example on CodePen

Of course, in this case, an ordered list would be much more appropriate, but you get the point. Now, if you’re worried about XSS and HTML escaping, read the docs for more info.

Loops

Jade provides an excellent looping syntax so that you don’t need to resort to JavaScript. Let’s loop over an array:

- var droids = ["R2D2", "C3PO", "BB8"];
div
  h1 Famous Droids from Star Wars
  for name in droids
    div.card
      h2= name

And this will compile as follows:

<div>
  <h1>Famous Droids from Star Wars</h1>
  <div class="card">
    <h2>R2D2</h2>
  </div>
  <div class="card">
    <h2>C3PO</h2>
  </div>
  <div class="card">
    <h2>BB8</h2>
  </div>
</div>

View this example on CodePen

You can iterate over objects and use while loops too. Check out the docs for more.

Interpolation

It can get annoying to mix JavaScript into text like this p= "Hi there, " + profileName + ". How are you doing?". Does Jade have an elegant solution for this? You bet.

- var profileName = "Danny Ocean";
div
  p Hi there, #{profileName}. How are you doing?

View this example on CodePen

Isn’t that neat?

Mixins

Mixins are like functions. They take parameters as input and give markup as output. Mixins are defined using the mixin keyword.

mixin thumbnail(imageName, caption)
  div.thumbnail
    img(src="/img/#{imageName}.jpg")
    h4.image-caption= caption

Once the mixin is defined, you can call the mixin with the + syntax.

+thumbnail("oceans-eleven", "Danny Ocean makes an elevator pitch.")
+thumbnail("pirates", "Introducing Captain Jack Sparrow!")

Which will output HTML like this:

<div class="thumbnail">
  <img src="/img/oceans-eleven.jpg">
  <h4 class="image-caption">
    Danny Ocean makes an elevator pitch.
  </h4>
</div>
<div class="thumbnail">
  <img src="/img/pirates.jpg">
  <h4 class="image-caption">
    Introducing Captain Jack Sparrow!
  </h4>
</div>

Putting It All Together

Let’s put together everything we’ve learned so far. Say we have a nice array of movies, with each item containing the movie’s title, the cast (a sub-array), the rating, the genre, a link to the IMDB page and the image path for the movie’s poster. The array will look something like this (white space added for readability):

- var movieList = [
  {
    title: "Ocean's Eleven",
    cast: ["Julia Roberts", "George Clooney", "Brad Pitt", "Andy Garcia"],
    genres: ["Comedy", "Thriller"],
    posterImage: "/img/oceans-eleven",
    imdbURL: "http://www.imdb.com/title/tt0240772/",
    rating: 7
  }
  // etc...
];

We have 10 movies and we want to build nice movie cards for each of them. Initially, we don’t plan to use the IMDB link. If a movie is rated above 5, we give it a thumbs up, otherwise, we give it a thumbs down. We’ll use all the nice features of Jade to write some modular code to do the following:

  1. Create a mixin for a movie card
    • Iterate through the cast list and display the actors. We’ll do the same with genres.
    • Check the rating and decide whether to display a thumbs up or a thumbs down.
  2. Iterate through the movie list and use the mixin to create one card per movie.

So let’s create the mixin first.

mixin movie-card(movie)
  div.movie-card
    h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
      each actor in movie.cast
        li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre

There’s a lot going on up there, but I’m sure it looks familiar – we’ve covered all this in this tutorial. Now, we just need to use our mixin in a loop:

for movie in movieList
  +movie-card(movie)

That’s it. Is that elegant or what? Here’s the final code.

- var movieList = [
  {
    title: "Ocean's Eleven",
    cast: ["Julia Roberts", "George Clooney", "Brad Pitt", "Andy Garcia"],
    genres: ["Comedy", "Thriller"],
    posterImage: "/img/oceans-eleven",
    imdbURL: "http://www.imdb.com/title/tt0240772/",
    rating: 9.2
  },
  {
    title: "Pirates of the Caribbean",
    cast: ["Johnny Depp", "Keira Knightley", "Orlando Bloom"],
    genres: ["Adventure", "Comedy"],
    posterImage: "/img/pirates-caribbean",
    imdbURL: "http://www.imdb.com/title/tt0325980/",
    rating: 9.7
  }
];

mixin movie-card(movie)
  div.movie-card
    h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
    each actor in movie.cast
      li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre

for movie in movieList
  +movie-card(movie)

And here’s the compiled HTML:

<div class="movie-card">
  <h2 class="movie-title">Ocean's Eleven</h2>
    <img src="/img/oceans-eleven" class="movie-poster"/>
  <h3>Cast</h3>
  <ul class="cast">
    <li>Julia Roberts</li>
    <li>George Clooney</li>
    <li>Brad Pitt</li>
    <li>Andy Garcia</li>
  </ul>
  <div class="rating">
    <img src="img/thumbs-up"/>
  </div>
  <ul class="genre">
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
</div>
<div class="movie-card">
  <h2 class="movie-title">Pirates of the Carribean</h2>
  <img src="/img/pirates-caribbean" class="movie-poster"/>
  <h3>Cast</h3>
  <ul class="cast">
    <li>Johnny Depp</li>
    <li>Keira Knightley</li>
    <li>Orlando Bloom</li>
  </ul>
  <div class="rating">
    <img src="img/thumbs-up"/>
  </div>
  <ul class="genre">
    <li>Adventure</li>
    <li>Comedy</li>
  </ul>
</div>

But wait a minute. What if we now want to go to the movie’s IMDB page when we click on a movie’s title? We can add one line: a(href=movie.imdbURL) to the mixin.

mixin movie-card(movie)
  div.movie-card
    a(href=movie.imdbURL)
      h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
    each actor in movie.cast
      li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre

View this example on CodePen

Conclusion

We went from knowing nothing about Jade to building some beautiful modular movie cards. There’s a lot more to Jade, but I’ve glossed over some concepts to keep things simple. So I hope this tutorial piqued your curiosity to learn more.

Important note: As some of you might already know, Jade has been renamed to Pug due to a software trademark claim. In the future, articles on Jade will use the new name “Pug” or “PugJS”.

More:
  • http://www.wictorzon.com Robert Wictorzon

    When I played with this I noticed that after div.rating the if-clause should be indented or the thumb-image ends up outside the div.

    • Sanjay Guruprasad

      Thanks Robert, you’re right – the indentation is wrong in the last example, we’ll fix it soon!

    • LouisLazaris

      Thanks for that correction. I’ve fixed it.

  • Sanjay Guruprasad

    Thanks a lot Evan, I’m glad you liked the article! Will be fixing (1) soon. And you’re right, I’ve missed out if statements in the “Loops and Conditionals” section. Will update the article soon :)

  • LouisLazaris

    Thanks I’ve added the “.jpg”.

    In regards to the conditionals… Yeah, I think Sanjay was intending to include info about that but I guess left it out and we forgot to change the headings to match. I’ve removed mention of “conditionals”. The later examples do use them, so that’s enough I think Thanks.

  • http://simonswiss.com simonswiss

    Very good introduction to Jade/Pug!

    For those of you who like learning by video – I created a free youtube series introducing Jade in very short (90 seconds!) clips which cover similar points: https://www.youtube.com/watch?v=JqCs1pdmf9o&list=PLHrxuCR-0CcSWiMuLf58iuIsNlP549-Sk

  • Joe Wang

    Hey, I got a question for template engine, I am new to web application, and I am now struggling to build my own website, currently I am using express in node.js. I have a index page that lists several projects, and every projects will send a url to server asking for the description web page when you click it. Now since most of them share the same background and style, on the description part is different, so I am thinking using only one html to be the page and based on different requests sent by projects, server and fetch data from database and insert it into html, which makes the html more like a template.

    Then I start learn template engine, like jade. However, I find a big concerns about this template engine stuff. For example, there are 10000 lines in that template html file, and only 2 lines of it is about description, what I think is the ideal solution is, using jade to generate html file only for the first time and save it in the server, then for each request the server doesn’t have to generate all other 9998 lines of code anymore, and everytime you just insert description info into that 2 lines without worry about regenerating all the other 9998 lines. But in express, it seems for every request, express will render .jade to html. Isn’t it too consuming, if there are bunch of requests asking for different descriptions?

    • Sanjay Guruprasad

      Hi Joe, you’re right, express will render the html every time – but this is what its designed to do. In most cases, you shouldn’t see any performance issues.

      Your idea of caching all the possible HTML files is an option – but that only makes sense if there are a limited number of possible files. You may run into other problems – for example, every time there is a change in the database, you need to update the cached files, otherwise the HTML and the database will go out of sync. Jade files compile into a function, and this function then acts on the “data” or “locals” that you pass to it. It’s built to be pretty efficient for server side rendering. I’ve used it in production without any issues for multiple websites.

      Are you facing any performance related problems at the moment?

      • Joe Wang

        Hi, thank you for the reply. There are something I don’t get quite well.
        First, I don’t quite get the caching part, what do you mean caching all the possible HTML files? sorry for my bad expression, the thing I wanna say is since most of the content of that html is static, which doesn’t change with different request, we can save that part, the 9998 lines part, as a file and leave the 2 lines part out for sql data injected into it, otherwise express will render the whole 10000 lines html for each request.

        Second, I don’t have any performance issues at the moment, just curious that is this way of dealing with dynamically data with a jade generated html a popular and decent way to handle problems in a large scale. For my personal website, it will be more than enough, but what if this website suddenly became popular and get thousands of visits every seconds?

        • Sanjay Guruprasad

          This should not really be a problem, even with thousands of visits per second. If you want to have a static HTML file and use client side rendering to inject the two lines (using an AJAX request and some client side javascript), then this is always an option. There are pros and cons to this approach (SEO for example), but you can explore that if you like. But if you want to do it server side, Jade will be very fast, because the entire file is compiled into a function which is now in memory. It will not be reading the jade file each time. Instead, it will simply be substituting the locals into the template and serving the output HTML, which will be extremely fast.

          To summarize, if the same user is going to visit multiple pages which are all identical, except for two lines, and you are really worried about performance, then you can fetch those two lines using an AJAX request and serve a static HTML page with some client side JS. If you are looking for a server side solution, Jade is probably your best bet.

          • Joe Wang

            Oh, thanks for the detailed explanation, I didn’t get the compile function before, now I understand. It is kinda like only compile one time, save static staff into the memory and leave blank to the dynamic content, right?

          • Joe Wang

            Hey Sanjay,

            I have a problem for pass value from node.js to variable in jade when the variable is declared in jade like “-var videoEnable = false;”. In this case, no matter either true of false I pass into jade, it doesn’t do anything to the “videoEnable” variable. This only take effect when I delete the line of declaration. I don’t think it is impossible but I cannot find a way to do that from google.

          • Sanjay Guruprasad

            Hey Joe,
            That’s because you are overriding the passed value with the new value (false). You don’t need to redeclare the value that you’re passing it to Jade. You can just use it directly.

Recommended
Sponsors
Get the latest in Front-end, once a week, for free.