Hiccup in pure Clojure
(require '[huff2.core :as h])
When it comes to hiccup libraries, there's a venn-diagram "has ergonomic and modern affordances" and "works on babashka". So huff is my way of saying why not both?
Weavejester's hiccup library runs on babashka, but is missing some of the newer features hiccup afficianados have come to demand.
Lambda Island's hiccup also provides a modern api, but overall I'd still call it a subset of huff's features.
[:div {:style {:font-size 30}}]
:div.a#id.b
or :div.a.c#id
or :#id.a.c
all work!lambdaisland/hiccup
)(list [:li.a] [:li.b])
[:<> [:li.a] [:li.b]]
[:. {:color :red}]
<div color=red></div>
Parse tags for id and class (in any order).
(h/html [:div.hello#world "!"])
;; => <div class="hello" id="world">!</div>
(println (h/html [:div.left-aligned>p#user-parent>span {:id "user-name"} "Jason"]))
;=> <div class="left-aligned"><p id="user-parent"><span id="user-name">Jason</span></p></div>
(h/html [:<> [:div "d"] [:<> [:<> [:span "s"]]]])
;; =>
<div>d</div><span>s</span>
This is useful for returning multiple elements from a function:
(defn twins [x] [:<>
[:div.a x]
[:div.b x]])
(h/html [:span.parent [twins "elements"]])
;;=>
<span class="parent">
<div class="a">elements</div>
<div class="b">elements</div>
</span>
Nest and combine them with lists to better convey intent to expand:
(h/html
[:ol
[:<> (for [x [1 2]]
[:li>p.green {:id (str "id-" x)} x])]])
;;=>
<ol>
<li>
<p id=\"id-1\" class=\"green\">1</p>
</li>
<li>
<p id=\"id-2\" class=\"green\">2</p>
</li>
</ol>
(h/html [:div {:style {:border "1px red solid"
:background-color "#ff00ff"}}])
;; => <div style="background-color:#ff00ff;border:1px red solid;"></div>
(h/html [:. {:style {:width 3}}])
;;=> <div style=\"width:3px;\"></div>
This is nice if you want to e.g. render markdown in the middle of your hiccup. Note: We disable this by default and it must be manually enabled in the call to html
or page
,
(h/html [:hiccup/raw-html "<div>raw</div>"])
;; =Throws=> :hiccup/raw-html is not allowed. Maybe you meant to set allow-raw to true?
(h/html {:allow-raw true} [:hiccup/raw-html "<div>raw</div>"])
;;=> <div>raw</div>
Another nice-to-have is to disallow raw html in un-trusted data getting passed into to the compiler, but being able to do that as a dev.
(h/html [:div [:hiccup/raw-html (h/raw-string "<!-- oops.")]])
;; => <div><!-- oops.</div>
[More Info]
Write a function that returns hiccup, and call it from the first position of a vector, like in reagent.
(defn str-info [s]
[:div.info
[:span (apply str (reverse s))]
[:pre.len "Length: " (count s)]])
(h/html [str-info "hello"])
;; =>
<div class="info">
<span>olleh</span>
<pre class="len">Length: 5</pre>
</div>
(h/html [:div {:style {:width (* 5 2)}}])
;;=> <div style="width:10px;"></div>
We now offer customization of the hiccup grammar.
With this power, you can write new tags that can parse (and validate) their inputs.
Let's say you really need a tag to count its children, and put that into the final html.
(def my-schema (h2e/add-schema-branch h/hiccup-schema :my/child-counter-tag))
(defmethod h/emit :my/child-counter-tag [append! [_ [_ values]] opts]
(append! "I have " (count values) " children."))
append!
takes strings and will append them internally during html generation.
;; call:
(h/html (custom-fxns! my-schema)
[:div>h1 [:my/child-counter-tag "one" "two" "three"]])
;; => <div><h1>I have 3 children.</h1></div>
This will be a little faster, and you should prefer it if your schema isnt dynamic.
;; build:
(let [my-fxns (custom-fxns! my-schema)]
(def my-html (fn my-html [hic] (h/html my-fxns))))
(my-html [:div>h1 [:my/child-counter-tag "one" "two" "three"]])
;; => <div><h1>I have 3 children.</h1></div>
More details in the huff extension tests.
Can you improve this documentation? These fine people already did:
Bryan Maass & Mykhaylo BilyanskyyEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close