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")

