Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

369 lines (250 sloc) 8.284 kb

jade(1) -- jade template engine


spot [-h|--help] [-v|--version] [-o|--obj STR] [-O|--out DIR] [-p|--path PATH] [-P|--pretty] [-c|--client] [-D|--no-debug]


translate jade the templates dir

$ jade templates

create {foo,bar}.html

$ jade {foo,bar}.jade

jade over stdio

$ jade < my.jade > my.html

jade over s

$ echo "h1 Jade!" | jade

foo, bar dirs rendering to /tmp

$ jade foo bar --out /tmp

compile client-side templates without debugging instrumentation, making the output javascript very light-weight. This requires runtime.js in your projects.

 $ jade --client --no-debug < my.jade


Tags are simply nested via whitespace, closing tags defined for you. These indents are called "blocks".

    a Foo
    a Bar

You may have several tags in one "block":

    a Foo
    a Bar
    a Baz


Tag attributes look similar to HTML, however the values are regular JavaScript, here are some examples:

a(href='') Google
a(class='button', href='') Google

As mentioned the attribute values are just JavaScript, this means ternary operations and other JavaScript expressions work just fine:

body(class=user.authenticated ? 'authenticated' : 'anonymous')
a( || '')

Multiple lines work too:


Multiple lines without the comma work fine:


Funky whitespace? fine:


Boolean attributes

Boolean attributes are mirrored by Jade, and accept bools, aka true or false. When no value is specified true is assumed. For example:

input(type="checkbox", checked)
// => "<input type="checkbox" checked="checked" />"

For example if the checkbox was for an agreement, perhaps user.agreed was true the following would also output 'checked="checked"':

 input(type="checkbox", checked=user.agreed)

Class attributes

The class attribute accepts an array of classes, this can be handy when generated from a javascript function etc:

classes = ['foo', 'bar', 'baz']
// => "<a class="foo bar baz"></a>"

Class literal

Classes may be defined using a ".CLASSNAME" syntax:

 // => "<div class="button"></div>"

Or chained:

 // => "<div class="large button"></div>"

The previous defaulted to divs, however you may also specify the tag type:

  h1.title My Title
  // => "<h1 class="title">My Title</h1>"

Id literal

Much like the class literal there's an id literal:

// => "<div id="user-1"></div>"

Again we may specify the tag as well:

  li: a(href='/home') Home
  li: a(href='/store') Store
  li: a(href='/contact') Contact

Finally all of these may be used in any combination, the following are all valid tags:

a.button#contact(style: 'color: red') Contact
a.button(style: 'color: red')#contact Contact
a(style: 'color: red').button#contact Contact

Block expansion

Jade supports the concept of "block expansion", in which using a trailing ":" after a tag will inject a block:

  li: a Foo
  li: a Bar
  li: a Baz


Arbitrary text may follow tags:

 p Welcome to my site


 <p>Welcome to my site</p>

Pipe text

Another form of text is "pipe" text. Pipes act as the text margin for large bodies of text.

  | This is a large
  | body of text for
  | this tag.
  | Nothing too
  | exciting.


<p>This is a large
body of text for
this tag.

Nothing too

Using pipes we can also specify regular Jade tags within the text:

  | Click to visit
  a(href='') Google
  | if you want.

Text only tags

As an alternative to pipe text you may add a trailing "." to indicate that the block contains nothing but plain-text, no tags:

  This is a large
  body of text for
  this tag.

  Nothing too

Some tags are text-only by default, for example script, textarea, and style tags do not contain nested HTML so Jade implies the trailing ".":

  if (foo) {

  body {
    padding: 50px;
    font: 14px Helvetica;

Template script tags

Sometimes it's useful to define HTML in script tags using Jade, typically for client-side templates.

To do this simply give the script tag an arbitrary type attribute such as text/x-template:

  h1 Look!
  p Jade still works in here!


Both plain-text and piped-text support interpolation, which comes in two forms, escapes and non-escaped. The following will output the in the paragraph but HTML within it will be escaped to prevent XSS attacks:

p Welcome #{}

The following syntax is identical however it will not escape HTML, and should only be used with strings that you trust:

p Welcome !{}

Inline HTML

Sometimes constructing small inline snippets of HTML in Jade can be annoying, luckily we can add plain HTML as well:

p Welcome <em>#{}</em>


To buffer output with Jade simply use = at the beginning of a line or after a tag. This method escapes any HTML present in the string.

p= user.description

To buffer output unescaped use the != variant, but again be careful of XSS.

p!= user.description

The final way to mess with JavaScript code in Jade is the unbuffered -, which can be used for conditionals, defining variables etc:

- var user = { description: 'foo bar baz' }
  - if (user.description) {
    h2 Description
    p.description= user.description
  - }

When compiled blocks are wrapped in anonymous functions, so the following is also valid, without braces:

 - var user = { description: 'foo bar baz' }
   - if (user.description)
     h2 Description
     p.description= user.description

If you really want you could even use .forEach() and others:

- users.forEach(function(user){
    p User #{} is #{user.age} years old
- })

Taking this further Jade provides some syntax for conditionals, iteration, switch statements etc. Let's look at those next!


Jade's first-class assignment is simple, simply use the = operator and Jade will var it for you. The following are equivalent:

- var user = { name: 'tobi' }
user = { name: 'tobi' }


Jade's first-class conditional syntax allows for optional parenthesis, and you may now omit the leading - otherwise it's identical, still just regular javascript:

user = { description: 'foo bar baz' }
  if user.description
    h2 Description
    p.description= user.description

Jade provides the negated version, unless as well, the following are equivalent:

- if (!(user.isAnonymous))
  p You're logged in as #{}

unless user.isAnonymous
  p You're logged in as #{}


JavaScript's for loops don't look very declarative, so Jade also provides its own for loop construct, aliased as each:

for user in users
    p user #{} is #{user.age} year old

As mentioned each is identical:

 each user in users

If necessary the index is available as well:

  for user, i in users

Remember, it's just JavaScript:

    for letter in ['a', 'b', 'c']
      li= letter
Jump to Line
Something went wrong with that request. Please try again.