Created: 2008-11-19 16:35
Updated: 2018-10-27 09:59
License: mit


A Clojure library for expanding expressive HTML templates into efficient code.


The clj-html library is being deprecated in favor of Hiccup. Hiccup implements essentially the same interface as clj-html, but uses a more advanced compiler/interpreter, handles certain markup edge cases better, and offers a more complete suite of helpers. The clj-html project will remain online through August 2010, but will not be updated.


A basic template

(use 'clj-html.core)

  [:div#content "Hello World"])

"<div id=\"content\">Hello World</div>"

A template with non-literal values:

(let [greeting "Hello from clj-html"]
      [:h1.greeting greeting]]))
"<div id=\"content\"><h1 class=\"greeting\">Hello from clj-html</h1></div>"

A template with sequences:

  [:ul {:type "letters"}
    (for [char '("a" "b" "c")]
      [:li char])])

"<ul type=\"letters\"><li>a</li><li>b</li><li>c</li></ul>"

A named template:

(defhtml header [text]
  [:h3 text])

(header "Heading")



The primary entry point into the clj-html.core library is the macro html, which expands into code that will render the given template, returning a string. html accepts a vararg list of forms, each of which will be expanded according to the following rules:

Any atom (string, number, etc.) or list (code) will be evaluated as-is. If it logically false then nothing is added to the html, otherwise the result is coerced to a string and added to the html output.

A vector with a keyword as its first element will be treated as markup tag syntax. A tag can use CSS syntax to declare an id and/or classes (:div#myid.myclass).

The second element in the vector is an optional literal map of additional attributes to add to the tag ([:link {:rel "stylesheet" :href "style.css"}]). Both the keys and values of the map can be either literal values or expressions to be computed during evaluation. If the value for a key is logically false, no text is added for that key/value pair. If the value is equal to true then the "attrname=\"attrname\"" convention is used.

The remaining values in the tag vector are considered the inner content of the tag and are expanded recursively.

If no inner forms are given ([:br]]) then the tag that is created is self-closing (<br />). Otherwise a wrapping tag is created.

Finally, note that html expects anything in tag bodies to evaluate to either a string or a seq of strings. Thus the following are valid:

clj-html.core also includes the htmli function, which accepts very similar arguments to html but operates as an interpreter instead of a compiler. The main use for 'htmli' is when you cannot express the attributes map as a literal map:

(defn user-helper [attrs user]
  (htmli [:p (merge attrs {:class "user"}) (:name user)]))

This will render correctly only with htmli because the attrs map is not literal, i.e. it is produced by a dynamic call to merge.


Copyright 2009-2010 Mark McGranaghan and released under an MIT license.

Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more