GitHub - borkdude/html: Html generation library inspired by squint's html tag (original) (raw)

html

Produce HTML from hiccup in Clojure and ClojureScript.

Clojars Project

Rationale

Squint andcherry support HTML generation as built-in functionality. Some people wanted this functionality in JVM Clojure and ClojureScript as well. That is what this library offers.

Benefits over some (but definitely not all) hiccup libraries may be:

Drawbacks of this library:

In this README, all example results are written as strings. In reality they are a borkdude.html.Html object which just contains a string. This is done to prevent issues with double-encoding.

Examples

(require '[borkdude.html :refer [html]])

(let [name "Michiel"] (html [:div {:color :blue :style {:color :blue}} [:p "Hello there " name [:ul [:li 1] (map (fn [i] (html [:li i])) [2 3 4])]]])) ;;=> "<div color="blue" style="color: blue;">

Hello there Michiel

"

Passing props

This library doesn't support dynamic creation of attributes in the same way that some hiccup libraries do. Rather, you have to use the special :& property to pass any dynamic properties, reminiscent of the JSX spread operator:

(let [m {:style {:color :blue} :class "foo"}] (html [:div {:class "bar" :& m}])) ;;=> "<div class="foo" style="color: blue;">"

Any static properties, like :class "bar" above function as a default which will be overridden by the dynamic map m.

Fragment

A fragment can be written in a similar way as JSX with :<> as the tag:

(html [:div [:<> "Hello " "world"]]) ;;=>

Hello world

Unsafe

Unsafe HTML (which won't be HTML-escaped) can be written with:

(html [:$ "]) ;;=> ""

Child components

Just use function calls for child components:

(defn child-component [{:keys [name]}] (html [:div "Hello " name]))

(defn App [] (html [:div [:div {:color :blue}] (child-component {:name "Michiel"})]))

(App) ;=> "

<div color="blue">
Hello Michiel
"

Child seqs

To render a sequence of child elements, use html to render the child element as well:

(html [:ul [:li 1] (map (fn [i] (html [:li i])) [2 3])]) ;;=> "

"

Performance

Despite the relative simplicity of this library, performance is quite good. Here is an informal benchmark against hiccup/hiccup:

(comment (defn ul [] (html [:ul [:li 1] (map (fn [i] (html [:li i])) [2 3])])) (time (dotimes [_ 10000000] (ul))) ;; ~3600ms

(defn ul-hiccup [] (hiccup2.core/html [:ul [:li 1] (map (fn [i] [:li i]) [2 3])])) (time (dotimes [_ 10000000] (ul-hiccup))) ;; ~5500ms )

Note that in hiccup/hiccups case, when we wrap the [:li i] element within a call to hiccup2.core/html as well, performance becomes similar as html since it can do a similar compile-time optimization.

Data reader

To install the #html reader, add the following to data_readers.cljc:

{html borkdude.html/html-reader}

Then you can write:

Note that these data readers aren't enabled by default since it's not recommended to use unqualified data readers for libraries since this can be a source of conflicts.

Complete HTML5 document

When using html, this library outputs HTML5. So [:br] compiles to <br>without a closing tag. Here is an example of how to to output a complete HTML5 document:

(html [:<> [:$ ""] [:html {:lang "en"} [:head [:meta {:charset "utf-8"}] [:title "Hi"]] [:body [:div "ok"] [:p "yes" [:br]]]]])

License

MIT, see LICENSE