Clojure and ClojureScript, everywhere.
Hoplon is a set of Clojure and ClojureScript libraries that pave over the web's idiosyncrasies and present a simpler way to design and build single-page web applications. Learn more on our wiki.
Custom HTML elements are regular functions and can be created and composed functionally with HLisp
Spreadsheet-like dataflow with the Javelin ClojureScript library. Intuitively model reactive behavior using cells and formulas.
Interact with the server with the Castra Clojure and ClojureScript library. Define functions on the server, call them from the client.
A simple custom element
Elements and custom elements are regular functions. The function below, loud
, accepts any number of children. It constructs and returns a div
containing the uppercased children
.
(defn loud [& children]
(div :css {:text-transform "uppercase"} children))
(loud "Lisp Can Do It")
A stateful custom element
In this example, the timer
function initializes a Javelin input cell and schedules it for periodic update using window.setInterval
. The text of the returned div
is attached reactively to seconds
through a formula cell created using cell=
.
defelem
is a convenience macro for creating functions that handle attribute arguments naturally.
(defelem timer [attrs children]
(let [start (or (:start attrs) 0)
seconds (cell start)]
(.setInterval js/window #(swap! seconds inc) 1000)
(div attrs (cell= (str "Seconds Elapsed: " seconds)))))
;; our first timer will start at 0 and count up
(p (timer :style "color: green;" :start 0))
;; start 3 more timers, each with different starting values
(apply ol (map li (for [r (range 1 4)] (timer :start r))))
- Seconds Elapsed: 1
- Seconds Elapsed: 2
- Seconds Elapsed: 3
An application
In this final example, todo-list
is a function that returns an instance of a simple todo list application. The application responds to user input by updating input cell values when DOM events occur.
The :change
event on the text input is attached to a function that updates the new-item
input cell as keystrokes occur.
The :click
event on the button is attached to a function that appends the value of new-item
to the end of todo-items
inside a dosync
. dosync
is a transactional construct that suspends the propagation of new values through the cell graph while updating multiple cells.
todo-items
are rendered as li
elements using the loop-tpl
macro. loop-tpl
efficiently maps dynamically-sized collections to DOM nodes.
(defelem todo-list [{:keys [title]} _]
(let [todo-items (cell [])
new-item (cell "")]
(div
(h3 (or title "TODO"))
(ul
(loop-tpl :bindings [todo todo-items]
(li todo)))
(input :type "text"
:value new-item
:change #(reset! new-item @%))
(button :click #(dosync
(swap! todo-items conj @new-item)
(reset! new-item ""))
(text "Add #~{(inc (count todo-items))}")))))
(todo-list :title "TODO List")