On this page:
12.1 Syntax
12.2 Templates

12 HAML🔗

 (require koyo/haml) package: koyo-lib

haml is a convenience macro for generating xexprs with less boilerplate. Its syntax is inspired by haml – whence its name – but if you’ve used Clojure’s hiccup or any similar templating language (like jade or pug), then haml will feel familiar to you.

12.1 Syntax🔗


(haml element ...+)

element = (selector maybe-attributes element ...)
  | (unless cond-expr e0 e ...)
  | (when cond-expr e0 e ...)
  | &html-entity-name
  | ,@expr
  | expr
selector = :tag-name
  | .class-name
  | .class-name-1.class-name-2.class-name-n#id
  | :tag-name.class-name
  | :tag-name.class-name#id
maybe-attributes = 
  | ([:attribute-name maybe-expr] ...)
Produces an x-expression.

Literal numbers and strings are returned unmodified:

> (haml 1)


> (haml "hello")


Identifiers that start with an & character are converted to symbols with the initial & removed:

> (haml &mdash)


Other identifiers are evaluated from the enclosing environment:

> (let ([a-symbol 'mdash])
    (haml a-symbol))


Element tags start with a colon:

> (haml
   (:h1 "Hello World"))

'(h1 () "Hello World")

Id and class attributes can be attached to a tag via a shorthand syntax:

> (haml
   (:h1.title#main-title "Hello World"))

'(h1 ((id "main-title") (class "title")) "Hello World")

Tag names are optional if a class name is provided, in which case the tag defaults to div:

> (haml
    (:h1.title "Hello World")))

'(div ((class "content")) (h1 ((class "title")) "Hello World"))

Repeated attributes are concatenated into a single value:

> (haml
     ([:class "hello"]
      [:data-example "1"]
      [:data-example "2"])
     "Hello World")))

'(div ((class "content")) (h1 ((class "title hello") (data-example "1 2")) "Hello World"))

Lists of elements can be spliced in using the ,@e syntax:

> (haml
     ,@(for/list ([it '("a" "b" "c")])
         `(li ,it)))))

'(div ((class "content")) (ul ((class "items")) (li "a") (li "b") (li "c")))

Expressions that don’t parse as elements are evaluated in place at runtime:

> (define (say-hi name)
    (format "Hi, ~a!" name))
> (haml
   (:h1 (say-hi "Bogdan")))

'(h1 () "Hi, Bogdan!")

The when and unless forms are special-cased so that they automatically splice their result, if any, into the enclosing expression:

> (for ([v '(#t #f)])
      (:h1 (when v "a") "title"))))

'(h1 () "a" "title")

'(h1 () "title")

Passing multiple elements to the haml macro produces a list of xexpr?s:

> (haml
   (:li "a")
   (:li "b"))

'((li () "a") (li () "b"))

Changed in version 0.10 of package koyo-lib: when, unless and unquote-splicing are now recognized by binding. The @-style splicing syntax is no longer supported.
Changed in version 0.17: Element attributes may now begin with an @ symbol.

12.2 Templates🔗

 (require koyo/haml-template) package: koyo-lib

HAML templates let you define templatized versions of the haml form.


(define-haml-template id element)

Defines a HAML template named id that expands to (haml element) on use. The element syntax is the same as for haml, but extended with a (slot) form that indicates where the contents of the template should go.

> (define-haml-template container
> (container
   (:strong "child 1")
   (:strong "child 2"))

'(div ((class "container")) (strong () "child 1") (strong () "child 2"))

Added in version 0.22 of package koyo-lib.



Within a HAML template, determines where the content of the template will go. Raises a syntax error when used outside of a define-haml-template form.