Introduction
There are times when you want to go and experiment with new frameworks, tools, languages or "a.n.other thing" and it all goes well until you try to get your head around the syntax. You look at the documentation or the reference section of the website/wiki/pdf and yes the basics are covered, but sometimes there is still not enough to answer your eager questions of "How Do I...?".
Hopefully things will soon become clear(er)!
What is Jade
As you may guess from the Introduction, Jade is a view engine or more specifically a templating engine. The authors describe it as "a terse and simple templating language with a strong focus on performance and powerful features". Node.js is a JavaScript event driven server technology and by using the Express module you can use an out of the box web application framework. The templates and web pages served to the callers are generated by the templating engine, which by default is configured to be Jade. There are many others available all with slightly different focus or goals which you can choose as you see fit, however this is outwith the scope of this article.
Putting it another way, Jade provides a method of writing cleaner markup which when called by the web application is converted to HTML compliant syntax for presenting to the browser.
To get a flavour of what is to come lets take a look at this very simple example:
HTML Markup | Jade Equivalent |
<!DOCTYPE html>
<html>
<head>
<title>Jade Demo</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body><h1>Welcome CodeProject</h1>
<p>Welcome to this Jade Article</p>
</body>
</html>
|
doctype html
html
head
title Jade Demo
link(rel='stylesheet', href='http://www.codeproject.com/stylesheet/style.css')
body
h1 Welcome CodeProject
p Welcome to this Jade Article
|
As you can see, it is clean, structured, no closing tags, no <> brackets.
Are you ready?
Document Structure
With the Jade templating system each Jade document has the .jade file extension. The content of the file is a whitespace indented structure, with each tag (generally, see Shortforming later) represented on a new line. Nested tags such as list items within an ordered list would be indented deeper than the parent tag. This can clearly be seen on the example above with the HTML
, HEAD
, TITLE
relationship.
You cannot mix and match whitespace, so either use tabs or spaces, it gets upset if you don't. See the note later on this.
Layouts and Block Content and Stylesheets
If you are a ASP developer, then you will be familiar with the concept of master pages. This concept can also be used within Jade. You might have a website that has common functionality that you wish to have on every page. Rather than including this content on every page you write, you simply refer to an existing layout template. This is achieved using the extends
keyword. In addition to this, the page may be broken up into sections, these sections can be referred to as blocks. The template engine will match up the relevant block
to content and populate accordingly. The 'content' is an arbitrary identifier given to the block.
For example, my index page might be wrapped by the generic site master layout in which case on the index page I could do;
extends layout
block content
h1 Hello World!
p Welcome to CodeProject Readers
The layout.jade would contain all the generic HTML markup;
doctype html
html
head
title Hello CodeProject
link(rel='stylesheet', href='http://www.codeproject.com/stylesheets/style.css')
body
block content
You can also see in the above example how we can refer to CSS stylesheets using the link tag. This would generate the following markup if you were to look at the browser page source;
<!DOCTYPE html>
<html>
<head>
<title>Hello CodeProject</title>
<link rel="stylesheet" href="http://www.codeproject.com/stylesheets/style.css">
</head>
<body>
<h1>Hello World!</h1>
<p>Welcome to CodeProject Readers</p>
</body>
</html>
NOTE: When working in Visual Studio, it is very easy to get caught out by using different whitespace methods, e.g. Tabs or Spaces, VS will throw an exception if you mix and match. I recommend that you turn on "View Whitespace" from the "Edit|Advanced" menu (hotkey CTRL+E,S).
Also, if you have used tabs, it is easy to convert this to spaces by using the "Untabify Selected lines" from the same menu.
You could also permanently set the text editor to use spaces instead of tabs.
Jade also supports include
, which simply tells the Jade engine to include another Jade file in the output, e.g.
include somefolder/somefile
would require the somefile.jade file in the somefolder to be added to the content.
You will also notice that in the examples above, reference to the layout file and the included files does not need to have the .jade extension, this is automatic.
Handling Javascript, Referencing Libraries
Many web pages nowadays cannot exist without reference to JavaScript libraries or have JavaScript functions embedded within them. Fortunately, Jade can handle these scenarios without any problem.
If we take the page above and wanted to reference jQuery and then use the jQuery document ready handler to display an alert, this is no problem. To the layout.jade we can add the reference to the jQuery library, I'll point it to the public CDN on the jQuery domain.
doctype html
html
head
title Hello CodeProject
link(rel='stylesheet', href='http://www.codeproject.com/stylesheets/style.css')
script(type='text/javascript', src='http://code.jquery.com/jquery-1.11.0.min.js')
body
block content
And on the index page add in the JavaScript jQuery ready handler and function to trigger the alert;
extends layout
block content
h1 Hello World!
p Welcome to CodeProject Readers
script(type='text/javascript').
$(document).ready(function() {
alert("Hello CodeProject!");
});
NOTE: If you are paying close attention you will notice that at the end of the script(...) reference you will see a period '.
', this has special meaning to the Jade parser that everything that follows (up to the next tag) is treated as part of the content for that element.
This period '.
' can also be used with other tags, for example the paragraph p
;
p.
This is some text in the paragraph and
it is continuing across more than one
line, but will appear as a continuous
paragraph in the output.
So far we have looked at the basic structure of Jade documents, used the Extend
and Block
keywords and also seen how we can reference CSS or JavaScript files and include other Jade files or JavaScript in the page.
Tags and Classes
Following on from where we were with the demo, let us now add some class information into the mix. On the index page, let us define a new style via the 'bigred' class and apply it to a new paragraph on the page;
extends layout
block content
h1 Hello World!
p Welcome to CodeProject Readers
script(type='text/javascript').
$(document).ready(function() {
alert("Hello CodeProject!");
});
p.bigred Another paragraph with some styling applied.
style.
.bigred
{
font-size: 1.5em;
color: red;
}
You can see the class is applied by simply appending the class name to the paragraph using the '.
', p.bigred
It is also possible to apply multiple different classes to the one tag by simply chaining the names of the classes. For example, lets define an italic class style and apply it to the same paragraph, using p.bigred.italic
;
extends layout
block content
h1 Hello World!
p Welcome to CodeProject Readers
script(type='text/javascript').
$(document).ready(function() {
alert("Hello CodeProject!");
});
p.bigred.italic Another paragraph with some styling applied.
style.
.bigred
{
font-size: 1.5em;
color: red;
}
.italic
{
font-style: italic;
}
If we take everything done so far, you can see how this all looks in the generated HTML output;
<!DOCTYPE html>
<html>
<head>
<title>Hello CodeProject</title>
<link rel="stylesheet" href="http://www.codeproject.com/stylesheets/style.css">
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js">
</script>
</head>
<body>
<h1>Hello World!</h1>
<p>Welcome to CodeProject Readers</p>
<script type="text/javascript">$(document).ready(function() {
alert("Hello CodeProject!");
});
</script>
<p>This is some text in the paragraph and
it is continuing across more than one
line, but will appear as a continuous
paragraph in the output.
</p>
<p class="bigred italic">Another paragraph with some styling applied.</p>
<style>.bigred
{
font-size: 1.5em;
color: red;
}
.italic
{
font-style: italic;
}</style>
</body>
</html>
Naming elements
You may of course want to give elements names. You may wish to reference them in code or just be able to see what is what. It is easy to name an element via its id
attribute by simply using the #
symbol. for example;
Jade | HTML |
p#IntroText This is the intro text paragraph
|
<p id="IntroText">This is the intro text paragraph</p>
|
This can of course be mixed with adding the class names. So now we have;
Jade | HTML |
p.underline#AnotherPara This is another named paragraph with a class applied.
|
<p id="AnotherPara" class="underline">This is another named paragraph with a class applied.</p>
|
The DIV
The DIV
element is probably one of the most commonly used tags now in web development. The Jade developers have also taken this into consideration. Simply starting with an identifier and optional class name will automatically render a div
.
Jade | HTML |
#MyDiv
#AnotherDiv.underline
|
<div id="MyDiv"></div>
<div id="AnotherDiv" class="underline"></div>
| |
Other Common Tags
We have already looked at paragraph tag p
in the examples above, let us take a look at some of the other common tags.
Ordered List (OL), Unordered List (UL), ListItem (LI)
In the same way as many of the other tags it is simply a case of starting on a new line and nesting to the appropriate indent. Let us create both of these types of list within their own div blocks and wrap them both up in another parent div;
Jade | HTML |
#ListExamples
#ULExample
ul
li This is a list item
li This is another list item
#OLExample
ol
li This is a list item
li This is another list item
|
<div id="ListExamples">
<div id="ULExample">
<ul>
<li>This is a list item</li>
<li>This is another list item</li>
</ul>
</div>
<div id="OLExample">
<ol>
<li>This is a list item</li>
<li>This is another list item</li>
</ol>
</div>
</div>
|
You can of course use the previous examples for naming and class handling against the elements as you see fit.
Image (IMG)
You can probably work out from what you have seen so far how the image tag can work. You specify the tag as normal, any class elements or name and then specify the image source as an attribute;
img.#SomeImage(src='http://www.codeproject.com/images/demoimage.png')
Multiple Attribute Handling and Input Elements
Starting with multiple attributes, it is a simple as specifying these as a list of comma separated key/value pairs enclosed within parenthesis against the tag. For example if you wanted to specify alt
and title
attributes against the image tag you would write;
img#SomeImageID(src='http://www.codeproject.com/images/demoimage.png', alt="This is an image ALT", title="This is the image Title")
You can also add a list of classes as an attribute or chain these to the end;
img#SomeImageID(src='http://www.codeproject.com/images/demoimage.png',alt="This is an image ALT",title="This is the image Title", class="AClass BClass CClass").DClass.EClass
With input elements you may have to specify which items are selected or checked. This can be achieved using simple attributes again. In the example below we will create a group of 3 radio buttons, each with their own element name, but part of the same group (meaning only 1 can be selected at a time), the second will be default selected;
input#Element1(type="radio", name="RadioGroup", checked=false)
input#Element2(type="radio", name="RadioGroup", checked=true)
input#Element3(type="radio", name="RadioGroup")
You will notice that both the first and last checked state have both been set to false using different approaches. Likewise, I could have just written checked
for the selected one.
NOTE: The comma is in fact optional and provided the key=value attributes are whitespace separated, Jade still renders everything correctly.
Shortforming Nested Tags
Jade developers have also thought of this. You might have for example an image that appears within a link. Instead of having the image on a new line you can short form this like a: img
Jade | HTML |
a#ImageLink(href="offsomewhere.htm"): img(src="someimage.png")
|
<a id="ImageLink" href="offsomewhere.htm"><img src="someimage.png"/></a>
|
Comments, Text and Raw HTML
Comments in HTML can be specified in a couple of ways, either single line or a block. The single line is expressed using a simple //
and the block use the same //
,but start the comment on a new indented line. There is also a third method that will only comment in the Jade markup, but not include it in the rendered HTML //-
, these can be seen below;
// Single Line comment.
//
This is a multiple line
comment that covers several
lines.
//- This comment will not appear in the html output.
There is also a time when you just want the text or HTML to be displayed 'as is' i.e. not formatted. To achieve this, we use the pipe character |
, it must also be on its own line or the pipe symbol will be considered as text;
| This text will show <em>as is</em> with the italics tags being rendered as text in the output.
p | This text will output with a pipe symbol showing
p
| This paragraph will not have a pipe symbol showing
What Else Can Jade Achieve
Rendering HTML is clearly handled very well, but templating engines need to do a whole lot more to become really useful.
Mixology with Mixins
Steady on, we are not making cocktails here, but we are talking about creating fragments of reusable markup that can be applied as required. The fragment is first defined using the mixin
keyword followed by a name and then the fragments are called using the +MixinName()
format.
Jade | HTML |
mixin ContactList
ul
li Bob
li Dave
li Frank
p Here is the contact list
+ContactList()
p Here is another contact list
+ContactList()
|
<p>Here is the contact list</p>
<ul>
<li>Bob</li>
<li>Dave</li>
<li>Frank</li>
</ul>
<p>Here is another contact list</p>
<ul>
<li>Bob</li>
<li>Dave</li>
<li>Frank</li>
</ul>
|
Script Execution in the template
Code can be executed in the template by starting the block with an -
, this is called Unbuffered code. For example to repeat a table row 3 times you might do;
Jade | HTML |
//Generate a table with 3 identical rows
table
- for(x=0;x<3;x++)
<tr><td>This is a row</td></tr>
|
<!--
<table>
<tr><td>This is a row</td></tr>
<tr><td>This is a row</td></tr>
<tr><td>This is a row</td></tr>
</table>
|
There are two other type of code, Buffered Escaped and Buffered Unescaped output. The escaped output will encode any HTML in the output stream and you guessed it, the unencoded won't. These two methods are identified by using the =
and !=
markup respectively.
Jade | HTML |
// Escaped output
- var Escaped = true
if Escaped
p= 'This html tag will become <div>escaped</div>!'
else
p= 'This wont be visible'
|
// Escaped output
<p>This html tag will become <div>escaped</div>!</p>
|
For the unescaped version, simply replace the p=
for p!=
Conditionals
You have already seen an example of this, we just did one in the example above! Jade also supports an unless
operation which carries out negation of the condition check;
Jade | HTML |
- var bob = 'woman'
unless bob == 'man'
p Bob is a not man!
|
<p>Bob is a not man!</p>
|
Iteration
Iteration can be accomplished by using the structure below;
Jade | HTML |
-var i = [1,2,3,4,5,6]
each value in i
li= 'This is item ' + value
|
<li>This is item 1</li>
<li>This is item 2</li>
<li>This is item 3</li>
<li>This is item 4</li>
<li>This is item 5</li>
<li>This is item 6</li>
|
Switch / Case
Jade uses the case...when...default
structure to shorthand the JavaScript switch.
Jade | HTML |
- var id = 3
case id
when 1
p This is 1
when 2
p This is 2
when 3
p This is 3
when 4
p This is 4
default
p There is no hope!
|
<p>This is 3</p>
|
Block Expansion
Block expansion is very similar to the shortforming earlier. Block expansion also makes use of the :
. If we look at the Switch case above and re-write it using block expansion it would look like this;
- var id = 3
case id
when 1: p This is 1
when 2: p This is 2
when 3: p This is 3
when 4: p This is 4
default: p There is no hope!
But what about things like Twitter Bootstrap Integration
Don't panic, this is all handled just fine. All you have to do is rewrite the requirements of the bootstrap markup in the Jade format. There is even a kind developer who has already converted a bunch of the default elements in Bootstrap to Jade. These can be found in Github at;
https://github.com/ALT-F1/bootstrap3-jade-node-express-grunt/tree/master/app/views/bootstrap3-templates
It doesn't really matter what you are using, If you follow the principles of Jade and strip out the end tags, the <> and place the ids or class, attributes as required you will get there!
The Jade Online Playground
It is definitely worth using the provided playground on the Jade website. You can type/paste snippets of Jade and see how the outputted HTML is presented. This is a great way to see if you are getting what you expect as you learn the syntax.
The playground can be found at: http://jade-lang.com/demo/[^] and it is simply a case of clicking and editing the Jade Input or Locals boxes.
Points of Interest
Use the Playground to test snippets, it gives a better indication of where problems occur in your markup than the current Visual Studio error messages!
I hope you find this useful, there are certainly things mentioned here that I picked up through trial and error while trying to wrangle with the Bootstrap conversion to Jade (before I discovered it had been done before!).
The more you use Jade, the simpler it does become and it does make for cleaner templates.
I just need to take it to a larger scale project to see how things go!
References
History
- 30th March 2016 - Online playground now supports case fall through, updated text. (https://github.com/pugjs/pug/issues/1363)
- 31st May 2014 - Tidy up, added case fall through though fix statement.
- 3rd February 2014 - Added Block Expansion reference.
- 31st January 2014 - typo fix, minor revisions, fall through bug reference link added.
- 29th January 2014 - first release.