Fork this page on GitHub

Jade Syntax

Jade is the daddy of HTML template engines for Scala

Like Haml and Scaml, Jade uses whitespace indentation to represent nested markup blocks.

HTML Elements

The common case in Jade is a line starts with an element name followed by a space and any text content to put in the element.

example

one
  two
    three Hey there

renders to

<one>
  <two>
    <three>Hey there</three>
  </two>
</one>

Any string is a valid element name; Jade will automatically generate opening and closing tags for any element.

HTML-style Attributes: ()

You can use HTML style attributes with elements by placing them inside ()

html(xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en")

Scala variables can be used by omitting the quotes. For example:

a(title=title href=href) Stuff

Complex expression are supported if you wrap them between the { and } characters.

example

li(counter={3+4}) Stuff

renders to

<li counter="7">Stuff</li>

You can also use #{} interpolation to insert complicated expressions in a HTML-style attribute:

span(class="widget_#{widget.number}")

HTML-style attributes can be stretched across multiple lines just like hash-style attributes:

script(type="text/javascript"
        src="javascripts/script")

Attributes: { } or ( )

This style of attributes comes from Haml / Jade. Brackets represent a Scala Map that is used for specifying the attributes of an element. Ruby hash syntax is used instead of Scala syntax to preserve a higher level of compatibility with the original Haml / Jade implementation. It is translated and evaluated as a Scala Map, so logic will work in it and local variables may be used. Quote characters within the attribute will be replaced by appropriate escape sequences. The hash is placed after the tag is defined.

example

html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}

renders to

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"></html>

Attribute hashes can also be stretched out over multiple lines to accommodate many attributes. However, newlines may only be placed immediately after commas.

example

script{:type => "text/javascript",
        :src  => "javascripts/script"}

renders to

<script type="text/javascript" src="javascripts/script"/>

This is the same the following

script(type="text/javascript"
        src="javascripts/script")

You can use both attribute syntaxes together if you really want:

a(title="Hello"){:href => "http://scalate.fusesource.org"} Stuff

Complex expression are supported if you wrap them between the { and } characters.

example

li{:counter={3+4}} Stuff

renders to

<li counter="7">Stuff</li>

Boolean Attributes

Some attributes, such as “checked” for input tags or “selected” for option tags, are “boolean” in the sense that their values don't matter - it only matters whether or not they're present. In HTML (but not XHTML), these attributes can be written as

<input selected>

To do this in Jade using hash-style attributes, just assign a Scala true value to the attribute:

input{:selected => true}

In XHTML, the only valid value for these attributes is the name of the attribute. Thus this will render in XHTML as

<input selected="selected"/>

To set these attributes to false, simply assign them to a Scala false value. In both XHTML and HTML

input{:selected => false}

will just render as

<input/>

HTML-style boolean attributes can be written just like HTML:

input(selected)

or using true and false:

input(selected=true)

Class and ID: . and #

The period and pound sign are borrowed from CSS. They are used as shortcuts to specify the class and id attributes of an element, respectively. Multiple class names can be specified in a similar way to CSS, by chaining the class names together with periods. They are placed immediately after the tag and before an attributes hash.

example

div#things
  span#rice Chicken Fried
  p.beans{ :food => "true" } The magical fruit
  h1.class.otherclass#id La La La

renders to

<div id="things">
  <span id="rice">Chicken Fried</span>
  <p class="beans" food="true">The magical fruit</p>
  <h1 id="id" class="class otherclass">La La La</h1>
</div>

And,

example

#content
  .articles
    .article.title Doogie Howser Comes Out
    .article.date 2006-11-05
    .article.entry
      Neil Patrick Harris would like to dispel any rumors that he is straight

renders to

<div id="content">
  <div class="articles">
    <div class="article title">Doogie Howser Comes Out</div>
    <div class="article date">2006-11-05</div>
    <div class="article entry">
      Neil Patrick Harris would like to dispel any rumors that he is straight
    </div>
  </div>
</div>

Implicit Div Elements

Because divs are used so often, they're the default elements. If you only define a class and/or id using . or #, a div is automatically used.

example

#collection
  .item
    .description What a cool item!

is the same as

div#collection
  div.item
    div.description What a cool item!

and is rendered to:

<div id="collection">
  <div class="item">
    <div class="description">What a cool item!</div>
  </div>
</div>

Weird Element Names: 'element'

Sometimes you have to generate markup with weird element names. Element names like <funny.element/>. Since Jade interprets the period as a class name for the element, the following example:

example

funny.element

renders to

<funny class="element"/>

does not give you the desired result of <funny.element/>. In these cases you must single quote the element name.

Example:

example

'funny.element'

renders to

<funny.element/>

Self-Closing Tags: /

The forward slash character, when placed at the end of a tag definition, causes the tag to be self-closed. For example:

example

br/
meta{"http-equiv" => "Content-Type", :content => "text/html"}/

renders to

<br/>
<meta http-equiv="Content-Type" content="text/html"/>

Some tags are automatically closed, as long as they have no content. meta, img, link, script, br, and hr tags are closed by default. This list can be customized by setting the ScamlOptions.autoclose option.

example

br
meta{"http-equiv" => "Content-Type", :content => "text/html"}

renders to

<br/>
<meta http-equiv="Content-Type" content="text/html"/>

Plain Text

A substantial portion of any HTML document is its content, which is plain old text. To add text to an element either add it after the element name (and optional attributes) or add it on a newline with the | prefix.

For example:

example

gee
  whiz
    | Wow this is cool!

renders to

<gee>
  <whiz>
    Wow this is cool!
  </whiz>
</gee>

Note that HTML tags are passed through unmodified as well. If you have some HTML you don't want to convert to Jade, or you're converting a file line-by-line, you can just include it as-is.

example

p
  <div id="blah">Blah!</div>

renders to

<p>
  <div id="blah">Blah!</div>
</p>

Whitespace Removal: > and <

> and < give you more control over the whitespace near a tag. > will remove all whitespace surrounding a tag, while < will remove all whitespace immediately within a tag. You can think of them as alligators eating the whitespace: > faces out of the tag and eats the whitespace on the outside, and < faces into the tag and eats the whitespace on the inside. They're placed at the end of a tag definition, after class, id, and attribute declarations but before / or =.

example

blockquote<
  div
    | Foo!

renders to

<blockquote><div>
  Foo!
</div></blockquote>

And:

example

img
img>
img

renders to

<img/><img/><img/>

And:

example

p<= "Foo\nBar"

renders to

<p>Foo
Bar</p>

And finally:

example

img
pre><
  | foo
  | bar
img

renders to

<img /><pre>foo
bar</pre><img />

Doctype: !!! format

When describing HTML documents with Jade, you can have a document type or XML prolog generated automatically by including the characters !!!.

example

!!! XML
!!!
html
  head
    title Myspace
  body
    h1 I am the international space station
    p Sign my guestbook

renders to

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>Myspace</title>
  </head>
  <body>
    <h1>I am the international space station</h1>
    <p>Sign my guestbook</p>
  </body>
</html>

You can also specify the specific doctype after the !!! When the format is set to :xhtml (the default), the following doctypes are supported:

!!!

XHTML 1.0 Transitional <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

!!! Strict

XHTML 1.0 Strict <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

!!! Frameset

XHTML 1.0 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

!!! 1.1

XHTML 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

!!! Basic

XHTML Basic 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">

!!! Mobile

XHTML Mobile 1.2
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">

When the format option is set to :html4, the following doctypes are supported:

!!!

HTML 4.01 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

!!! Strict

HTML 4.01 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

!!! Frameset

HTML 4.01 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">

!!! 5

HTML 5
<!DOCTYPE html>

When the format option is set to :html5, !!! is always <!DOCTYPE html>.

If you're not using the UTF-8 character set for your document, you can specify which encoding should appear in the XML prolog in a similar way.

example

!!! XML iso-8859-1

renders to

<?xml version="1.0" encoding="iso-8859-1" ?>

Comments

Jade supports two sorts of comments: those that show up in the HTML output and those that don't.

HTML Comments: /

The forward slash character, when placed at the beginning of a line, wraps all text after it in an HTML comment.

example

peanutbutterjelly
  / This is the comment
  | I like sandwiches!

renders to

<peanutbutterjelly>
  <!-- This is the comment -->
  I like sandwiches!
</peanutbutterjelly>

The forward slash can also wrap indented sections of code. For example:

example

/
  p This doesn't render...
  div
    h1 Because it's commented out!

renders to

<!--
  <p>This doesn't render...</p>
  <div>
    <h1>Because it's commented out!</h1>
  </div>
-->

Conditional Comments: /[]

You can also use Internet Explorer conditional comments by enclosing the condition in square brackets after the /.

example

/[if IE]
  a{ :href => "http://www.mozilla.com/en-US/firefox/" }
    h1 Get Firefox

renders to

<!--[if IE]>
  <a href="http://www.mozilla.com/en-US/firefox/">
    <h1>Get Firefox</h1>
  </a>
<![endif]-->

Jade Comments: -#

The hyphen followed immediately by the pound sign signifies a silent comment. Any text following this isn't rendered in the resulting document at all.

For example:

example

p foo
-# This is a comment
p bar

renders to

<p>foo</p>
<p>bar</p>

You can also nest text beneath a silent comment. None of this text will be rendered.

example

p foo
-#
  This won't be displayed
    Nor will this
p bar

renders to

<p>foo</p>
<p>bar</p>

Scala Evaluation

Binding Attributes -@

When a Scalate template is rendered, the caller can pass an attribute map which the template in charge of rendering. To bind the attribute to a Scala variable, a Jade template uses the hyphen character followed by a ampersand character and then a scala variable declaration statement.

For example To define an attribute use the following declaration

-@ val foo: MyType 

If the attribute map does not contain a “foo” entry, then a NoValueSetException is thrown when the the template is rendered.

To avoid this exception, a default value can be configured. For example:

-@ val bar: String = "this is the default value"

The attribute is now available for use as an expression.

Its very common to have a template based on a single object who's members are f frequently accessed. In this cases, it's convenient to import all the object's members. This can be done by adding the import keyword to the attribute declaration.

For example:

-@ import val model: Person
p Hello #{name}, what is the weather like in #{city}

is the same as:

-@ val model: Person
- import model._
p Hello #{name}, what is the weather like in #{city}

Which is the same as:

-@ val model: Person
p Hello #{model.name}, what is the weather like in #{model.city}

Inserting Scala: =

The equals character is followed by Scala code. This code is evaluated and the output is inserted into the document.

example

p
  = List("hi", "there", "reader!").mkString(" ")
  = "yo"

renders to

<p>
  hi there reader!
  yo
</p>

The default setting for the TemplateEngine.escapeMarkup option is true. When TemplateEngine.escapeMarkup is enabled, = will sanitize any HTML-sensitive characters generated by the script.

example

= """<script>alert("I'm evil!");</script>"""

renders to

&lt;script&gt;alert(&quot;I'm evil!&quot;);&lt;/script&gt;

= can also be used at the end of a tag to insert Scala code within that tag.

example

p= "hello"

renders to

<p>hello</p>

Running Scala: -

The hyphen character is also followed by Scala code. This code is evaluated but not inserted into the document.

**It is not recommended that you use this widely; almost all processing code and logic should be restricted to the Controller, the Helper, or partials.**

example

- var foo = "hello"
- foo += " there"
- foo += " you!"
p= foo

renders to

<p>hello there you!</p>

Or alternatively, if you have a large block of Scala code, you can nest it under the hyphen character as demonstrated by the following example:

example

-
  var foo = "hello"
      foo += " there"
  foo += " you!"
p= foo

renders to

<p>hello there you!</p>

Scala Blocks

Scala blocks, like XHTML tags, don't need to be explicitly closed in Jade. Rather, they're automatically closed, based on indentation. A block begins whenever the indentation is increased after a Scala insertion or evaluation command. It ends when the indentation decreases.

example

- for(i <- 42 to 46)
  p= i
p See, I can count!

renders to

<p>42</p>
<p>43</p>
<p>44</p>
<p>45</p>
<p>46</p>
<p>See, I can count!</p>

And,

example

p
  - 2 match
    - case 1 =>
      = "one"
    - case 2 =>
      = "two"
    - case 3 =>
      = "three"

renders to

<p>
  two
</p>

When inserting evaluated statements, it can also take advantage of Scala blocks. It can be handy for passing partial functions.

For example:

p
  = List(1,2,3).foldLeft("result: ")
    - (a,x)=>
      - a+x 

is the same as:

p
  = List(1,2,3).foldLeft("result: ") { (a,x)=> { a+x } }

would be rendered to:

<p>
  result: 123
</p>

Scala Interpolation: #{}

Scala code can be interpolated within plain text using #{}.

example

p This is #{quality} cake!

is the same as

p= "This is the "+(quality)+" cake!"

and renders to

<p>This is scrumptious cake!</p>

Backslashes can be used to escape #{ strings, but they don't act as escapes anywhere else in the string.

example

p
  A slash make a difference here: \#{name} is set to: \\#{name}
  But is ignored for: \# or \\

renders to

<p>
  A slash make a difference here: #{name} is set to: \Hiram
  But is ignored for: \# or \\
</p>

Whitespace Preservation in expressions: ~

~ works just like =, except that it preserves the white space formating on its input.

Jade always produces HTML source which is easy to read since it properly indented. Even dynamically generated output is properly indented.

example

html
  p
    = "line1\nline2\nline3"

renders to

<html>
  <p>
    line1
    line2
    line3
  </p>
</html>

Sometimes you don't want Jade to indent the dynamically generated content. For example, tags like pre and textarea are whitespace-sensitive; indenting the text makes them render wrong.

When you use ~ instead of =, Jade will convert newlines to the XHTML newline escape code, and avoid adding spaces for indentation.

example

html
  pre
    ~ "line1\nline2\nline3"

renders to

<html>
  <pre>
    line1&#x000A;line2&#x000A;line3
  </pre>
</html>

Ugly Preservation: ~~

Sometimes, you don't want Jade to indent or apply the whitespace transformation on the evaluated expression. When this is the case, use ~~ to use ugly whitespace preservation. We call it ugly because the produce HTML will not properly indented.

example

html
  p
    ~~ "line1\nline2\nline3"

renders to

<html>
  <p>
line1
line2
line3
  </p>
</html>

Escaping HTML: &=

An ampersand followed by one or two equals characters evaluates Scala code just like the equals without the ampersand, but sanitizes any HTML-sensitive characters in the result of the code.

example

&= "I like cheese & crackers"

renders to

I like cheese &amp; crackers

When the TemplateEngine.escapeMarkup option is set to true, = behaves identically to &=.

& can also be used on its own so that #{} interpolation is escaped.

example

& I like #{"cheese & crackers"}

renders to

I like cheese &amp; crackers

Unescaping HTML: !=

An exclamation mark followed by one or two equals characters evaluates Scala code just like the equals would, but never sanitizes the HTML.

When the TemplateEngine.escapeMarkup option is set to false, = behaves identically to !=.

However, if the TemplateEngine.escapeMarkup option is set to true, = will sanitize the HTML, but != still won't.

For example, if TemplateEngine.escapeMarkup is true:

example

= "I feel <strong>!"
!= "I feel <strong>!"

renders to

I feel &lt;strong&gt;!
I feel <strong>!

! can also be used on its own so that #{} interpolation is unescaped.

example

! I feel #{"<strong>"}!

renders to

I feel <strong>!

Filters: :

The colon character designates a filter. This allows you to pass an indented block of text as input to another filtering program and add the result to the output of Haml.

The syntax is a colon followed by an optional list of filter flags and then a colon separated list of filter names.

example

p
  :markdown
    Markdown
    ========
    
    Hello, *World*

renders to

<p>
  <h1>Markdown</h1>

  <p>Hello, <em>World</em></p>
</p>

Or if you want to generate JavaScript from CoffeeScript…

example

body
  :coffeescript
    alert "Hello, Coffee!"

renders to

<body>
  <script type='text/javascript'>
    //<![CDATA[
      (function() {
        alert("Hello, Coffee!");
      }).call(this);

    //]]>
  </script>
</body>

Filter Interpolation

If you use the ! or & filter flags, you can have Scala code interpolated with #{} expressions. It is invalid to use both the ! and & flags at the same time.

The & flag enables sanitized interpolations.

example

- var flavor = "<raspberry/>"
#content
  :&markdown
    I *really* prefer #{flavor} jam.

renders to

<div id="content">
  <p>I <em>really</em> prefer &lt;raspberry/&gt; jam.</p>
</div>

The ! flag enables non-sanitized interpolations.

example

- var flavor = "<raspberry/>"
#content
  :!markdown
    I *really* prefer #{flavor} jam.

renders to

<div id="content">
  <p>I <em>really</em> prefer <raspberry/>; jam.</p>
</div>

Filter Whitespace Preservation

The ~ filter flag enables preserves the white space of the content. The indent level is left unchanged and newlines are converted to

example

html
  p<
    :~plain
          Indentation levels are not enforced in filters.
        #{Interpolation} is disabled by default
      Last line

renders to

<html>
  <p>    Indentation levels are not enforced in filters.&#x000A;  #{Interpolation} is disabled by default&#x000A;Last line</p>
</html>

Filter Chaining

More than one filter can be be used by separating each filter name with a colon. When this is done, the filters are chained together so that the output of filter on right, is passed as input to the filter on the left.

example

pre
  :escaped :javascript
    alert("Hello");

renders to

<pre>
  &lt;script type='text/javascript'&gt;
    //&lt;![CDATA[
      alert(&quot;Hello&quot;);
    //]]&gt;
  &lt;/script&gt;
</pre>

Available Filters

Scalate has the following filters defined:

:plain

Does not parse the filtered text. This is useful for large blocks of text or HTML. Really handy when when you don't want lines starting with . or - to be parsed.

:javascript

Surrounds the filtered text with <script> and CDATA tags. Useful for including inline Javascript.

:css

Surrounds the filtered text with <style> and CDATA tags. Useful for including inline CSS.

:cdata

Surrounds the filtered text with CDATA tags.

:escaped

Works the same as plain, but HTML-escapes the text before placing it in the document.

:sass

Parses the filtered text with Sass to produce CSS output.
Only works if you have the scalate-jruby module on the class path. You normally want to combine with the :css filter. For example :css:sass

:scss

Parses the filtered text with Scss to produce CSS output. Only works if you have the scalate-jruby module on the class path. You normally want to combine with the :css filter. For example :css:scss

:textile

Parses the filtered text with Textile. Only works the scalate-wikitext module is found on the class path.

:markdown

Parses the filtered text with Markdown. Only works if scalamd or MarkdownJ is found on the class path.

Global Jade and Scaml Options

There are several global options you can configure to customize how Jade and Scaml renders the output. You will need to configure these before any of your scaml templates are compiled as they affect the generated scala template classes.

ScamlOptions.indent

The ScamlOptions.indent option is used to control what kind of indenting characters to use in the rendered markup. It defaults to two spaces but can be set to the tab character or set to the empty string to disable indenting alltogether.

ScamlOptions.indent = ""

gee
  whiz
    | Wow this is cool!

renders to

<gee>
<whiz>
Wow this is cool!
</whiz>
</gee>

ScamlOptions.nl

The ScamlOptions.nl option is used to control what kind of new line seperator to use in the rendered markup. It defaults to \n. Some folks may want to set it and the indent to the empty string to reduce the generated document sizes.

For example, if ScamlOptions.indent = "" and ScamlOptions.nl = "" then:

example

gee
  whiz
    | Wow this is cool!

renders to

<gee><whiz>Wow this is cool!</whiz></gee>

ScamlOptions.ugly

Enabling the ScamlOptions.ugly option makes = statements work like ~~ statements. The dynamic expressions will not be indented and they the new line preservation transformation method will not be applied. Enabling the ugly option will significantly reduce the CPU overhead of processing dynamic expressions.

ScamlOptions.ugly = true

html
  p
    = "line1\nline2\nline3"

renders to

<html>
  <p>
line1
line2
line3
  </p>
</html>

Differences from JavaScript Jade

The Scalate flavour of Jade diverges a little in a few places from Jade implementation in JavaScript mostly around the area of filters.

In Scalate, the contents of a filter (like :markdown or :javascript) is assumed to be text, so there is no need to prepend the | symbol to each line.

Scalate Jade

!!! 5
html(lang="en")
  head
    title= pageTitle
    :javascript
      if (foo) {
         bar()
      }
  body
    h1 Jade - node template engine

JavaScript Jade

!!! 5
html(lang="en")
  head
    title= pageTitle
    :javascript
      | if (foo) {
      |    bar()
      | }
  body
    h1 Jade - node template engine

Other Resources