Skip to content

achin/clj-html

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

clj-html

Fast HTML templates in Clojure

Overview

A Clojure library for expanding expressive markup templates into efficient code,
drawing on the functional interface and markup syntax of compojure’s html
library
and the compilation
approach of cl-who.

Examples

A simple template:


(html
  [:body [:div#content "Hello World"]])

; expands to:
(let* [html-builder (StringBuilder.)]
(.append html-builder “”content\“>Hello World”)
(.toString html-builder))

;evaluates to:
“”content\“>Hello World”

A template with non-literal values:
<pre> (html [:body [:div#content [:h1.greeting greeting] [:p.message message]]]))

; expands to:
(let* [html-builder (StringBuilder.)]
(.append html-builder “”content\“>”greeting\“>”)
(if-let [content__148 greeting] (.append html-builder content__148))
(.append html-builder “”message\“>”)
(if-let [content__148 message] (.append html-builder content__148))
(.append html-builder “

”)
(.toString html-builder))

; evaluates to (with greeting bound to “Hello” and message to “from clj-html”):
“”content\“> \
”greeting\“>Hello \
”message\">from clj-html

\

"

A more involved template:


(html
  [:body
    [:div#examples
      [:p.string "foo"]
      [:p.literal 3]
      [:p.expression (str "clj" "-" "html")]
      [:ul#sequence
        (domap-str [char '(a b c)]
          (html [:li char]))]]])

; expansion omitted, evaluation as expected.

Details – Core

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 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"}]). The keys must be literal keywords, though the values 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.

clj-html.core also includes the htmli, accepts very similar arguments to html but operates as an interpreter instead of a compiler. For a discussion of the tradeoffs between these two, see this Gist.

Details – Utils

clj-html.utils provides general helper methods that are useful for a variety of templating tasks, mostly for use with the html macro.

The function map-str is the usual map with a call to (apply str ...) in front. This is useful for rendering a sub-template for each element of a collection:


(defn person-template [person]
  (html
    [:div.person {:id (:id person)}
      [:p.name (:name person)]
      [:p.city (:city person)]]))

(html
  [:div#people
    (map-str person-template people)])

The macro domap-str is useful for rendering an inline snippet for
each element of a collection. domap-str has semantics like
map-str and a syntax like doseq. Note that since the
html macro does not reach within code, if you need to use the
literal vector syntax within a domap-str body you will need to use
html again.


(html
  [:div#people
    (domap-str [person people]
      (html [:div.person {:id (:uid person)}
              [:p.name (:name person)]
              [:p.city (:city person)]]))])

Also included are several methods of the form *-html*. These are designed to reduce the need for eg:


(html
  [:div
    (when urgent 
      (html
        [:h3 "Urgent!"]))])

; with when-html becomes
(html
[:div
(when-html urgent
[:h3 “Urgent!”])])

Currently we have if-html, when-html, when-let-html, and for-html.

Finally, you can use defhtml to define methods that are html templates without needing to include the outer html manually:


(defhtml message [text]
  [:div#message
    [:p.text text]])

Dependencies

Include recent versions of Clojure and Clojure Contrib in your classpath.

The test suite uses clj-unit, though you won’t need to use the library in general.


Copyright 2009 Mark McGranaghan and released under an MIT license.

About

Fast HTML templates in Clojure.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Clojure 100.0%