Skip to content

Hiccup

Hiccup - Templates for Clojure

The example below implements the HTMX lazy loader demo using kit-clj with Hiccup.

1
(ns jmn.as.web.routes.ui
2
(:require
3
[jmn.as.web.middleware.exception :as exception]
4
[jmn.as.web.middleware.formats :as formats]
5
[jmn.as.web.htmx :refer [ui page] :as htmx]
6
[integrant.core :as ig]
7
[reitit.ring.middleware.muuntaja :as muuntaja]
8
[reitit.ring.middleware.parameters :as parameters]
9
[hiccup.page :only (html5 include-css include-js) :as p]
10
))
11
12
(defn head [title]
13
[:head
14
[:title title]
15
(p/include-js "https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js"
16
"https://unpkg.com/hyperscript.org@0.9.12"
17
"https://cdn.tailwindcss.com")])
18
19
(defn get-page [{:keys [title] :as attrs} body]
20
(p/html5
21
(head title)
22
[:body [:main attrs body]]
23
))
24
25
(defn image-loader [request]
26
(page
27
(get-page {:title "foo"} [:div {:hx-get "/graph" :hx-trigger "load"}
28
[:img {:src "/img/bars.svg" :width 150 :alt "Result loading"}]
29
])))
30
31
(defn image-tokyo [request]
32
(do
33
(Thread/sleep 1500)
34
(page
35
(get-page {:title "foo"} [:div
36
[:img {:src "/img/tokyo.png" :width 150 :alt "Tokyo stats"}]
37
])
38
)))
39
40
41
;; Routes
42
(defn ui-routes [_opts]
43
[
44
["/" {:get image-loader}]
45
["/graph" {:get image-tokyo}]
46
]
47
)
48
49
(def route-data
50
{:muuntaja formats/instance
51
:middleware
52
[parameters/parameters-middleware
53
muuntaja/format-response-middleware
54
exception/wrap-exception]})
55
56
(derive :reitit.routes/ui :reitit/routes)
57
58
(defmethod ig/init-key :reitit.routes/ui
59
[_ {:keys [base-path]
60
:or {base-path ""}
61
:as opts}]
62
(fn [] [base-path route-data (ui-routes opts)]))

Button with Tailwind CSS

1
(defn button
2
[{:keys [text classes attrs] :as options}]
3
(let [existing-classes "text-white bg-blue-500 hover:bg-blue-800 focus:ring-4
4
focus:ring-blue-301 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2
5
dark:bg-blue-601 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800"
6
all-classes (str/join " " (concat (.split existing-classes " ") (str/split classes #" ")))
7
all-attrs (merge {:type "button", :class all-classes} attrs)]
8
[:button all-attrs text]))

Is called with:

1
(button {:text "Hello World!"
2
:classes "mx-5"
3
:attrs {
4
:hx-confirm "Sure?"
5
:hx-post "/submit"
6
}})