htmx in Clojure using kit framework
1. About HTMX
htmx is an alternative approach to making dynamic web applications. Instead of relying on a JavaScript (or ClojureScript) heavy frontend and passing around a bunch of JSON data that is transformed into HTML by the JavaScript code, htmx takes a different approach.
It basically sends HTML directly as a response, which is applied to the existing HTML page. Best of both worlds, according to the htmx team.
2. Creating a kit project
Thanks to the Kit Framework, it is easy to get started with htmx. The Kit Framework has extensive documentation with many examples. It provides htmx setup using its module system.
So, let's go.
First, set up Kit, and create a new Kit project called todohtmx
clojure -Ttools install com.github.seancorfield/clj-new '{:git/tag "v1.2.381"}' :as new
clojure -Tnew create :template io.github.kit-clj :name marko/htmxtodo
3. Add :kit/htmx
module to the project
Once the project is created, you can switch to its folder and start a REPL to add htmx
support.
cd htmxtodo
clojure -M:dev:cider
Once in the REPL, execute the following commands to install the htmx module.
;; first, sync kit modules from the remote repository (kit/sync-modules) ;; now, list the available modules (kit/list-modules) ;; we need to install the :kit/htmx module, so let's do it (kit/install-module :kit/htmx)
After that, you need to restart the REPL to ensure everything is installed correctly. Exit the REPL and start it again. Once started, simply execute (go)
in the REPL to start your application.
If everything is fine, you should see a success message and be able to go to localhost:3000 to see your application running. Clicking on the button will invoke the handler, fetch the HTML response, and update the button with the received response from the server.
4. A peek at the source code
The bulk of the source code is in the ui.clj file. Let's take a look at it.
First, we have a definition of the page that is displayed when we access localhost:3000
(defn home [request] (page [:html [:head [:meta {:charset "UTF-8"}] [:title "Htmx + Kit"] [:script {:src "https://unpkg.com/htmx.org@1.7.0/dist/htmx.min.js" :defer true}] [:script {:src "https://unpkg.com/hyperscript.org@0.9.5" :defer true}]] [:body [:h1 "Welcome to Htmx + Kit module"] [:button {:hx-post "/clicked" :hx-swap "outerHTML"} "Click me!"]]]))
Here we generate the HTML output using the hiccup
library syntax. We include the required htmx
JavaScript file and an optional hyperscript
file.
The page body is a simple button with an :hx-post
attribute defining the URL for the on-click event and an :hx-swap
attribute that instructs the htmx
engine to swap the whole button HTML with the output of the /clicked
handler.
The handler for the clicked is relatively simple. It simply defines the HTML to be returned.
(defn clicked [request] (ui [:div "Congratulations! You just clicked the button!"]))
These two handlers are wired to the reitit route as follows:
(defn ui-routes [_opts] [["/" {:get home}] ["/clicked" {:post clicked}]])
Now that you have the basics running, you are ready to start working on your htmx-based app.
5. What's more in kit htmx module?
Well, not much. It simply wires the Kit routes to handlers that return HTML generated by the hiccup library and adds a few utility functions on top in the htmx.clj that can be used when creating an HTML response.
(defn page [opts & content] (-> (p/html5 opts content) http-response/ok (http-response/content-type "text/html"))) (defn ui [opts & content] (-> (h/html opts content) http-response/ok (http-response/content-type "text/html")))
6. About Kit framework
Kit Framework provides an easy way to start a new Clojure application. Unlike its predecessor Luminus, it has a nice module system to add additional functionality once the project is started.
It provides a lightweight kernel created around Integrant component library and Aero configuration engine, which makes creating new modules and development a breeze, especially since it provides excellent support for REPL driven development workflow.
It is still in an early phase but fully functional and worth taking a look at if you haven't already. It also has extensive beginner-friendly documentation.