Skip to content
Experimental ClojureScript wrapper for modern React.js
Branch: master
Clone or download
Latest commit f9c3144 May 24, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci config May 24, 2019
.github Create FUNDING.yml May 24, 2019
core readme May 24, 2019
dom readme May 24, 2019
.gitignore monorepo May 24, 2019
.nvmrc Add .nvmrc to make it easier to use the same version than CircleCI May 24, 2019 Create May 9, 2019 update readme May 24, 2019
logo.png Add files via upload Apr 24, 2019

Experimental ClojureScript wrapper for modern React.js

Bug reports, feature requests and PRs are welcome 👌

There are no versioned releases yet, use deps.edn to depend on the code via git deps.

{:deps {uix.core {:git/url ""
                  :deps/root "core"
                  :sha "{{commit hash}}"}
        uix.dom {:git/url ""
                 :deps/root "dom"
                 :sha "{{commit hash}}"}}}


API Documentation

(require '[uix.core.alpha :as uix])
(require '[uix.dom.alpha :as uix.dom])

(defn button [{:keys [on-click]} text]
  [:button.btn {:on-click on-click}

(defn app []
  (let [state* (uix/state 0)]
      [button {:on-click #(swap! state* dec)} "-"]
      [:span @state*]
      [button {:on-click #(swap! state* inc)} "+"]]))

(uix.dom/render [button {:on-click js/console.log} "button"] js/root)



Hiccup syntax extension

  • [:div#id.class] or [:#id.class]
  • [:> js/Component attrs & children] - interop with JS components
  • [:<> attrs & children] - React.Fragment
  • [:-> element :#selector] or [:-> element dom-node] - React.createPortal
  • [:# {:fallback element} & children] - React.Suspense


React Hooks in idiomatic Clojure style

;; state hook
;; (mutable ref type, re-renders component when mutated)
(let [state (uix/state 0)]
  (swap! state inc)
  @state) ; 1

;; ref hook
;; (mutable ref type, doesn't cause re-renders)
(let [ref (uix/ref 0)]
  (swap! ref inc)
  @ref) ; 1

;; effect hook
  (fn []
    (prn "after update")
    #(prn "before unmount"))

;; convenience macro for uix.core/effect!
(uix/with-effect [deps]
  (prn "after update")
  #(prn "before unmount"))

;; more in uix.core.alpha ns

Attributes syntax extension

Injects provided function into attributes transformation stage. Could be used for various side effects, such as processing styles with CSS-in-JS libraries (see

  (fn [attrs]
    (my-transform-attrs attrs)))

Hiccup pre-compilation (advanced)

NOTE: UIx interpreter is already super fast (2x faster than Reagent and only 1.5x slower than vanilla React). Use pre-compilation ONLY if you are hitting performance problems.

Optionally compiles Hiccup into inlined React elements at compile-time

  [:h1 "Title"])

;; emits this
  $$typeof: Symbol.for("react.element"),
  key: null,
  ref: null,
  props: { children: "Title" },
  _owner: null

Compiler will try to inline as much as possible based on type information provided by ClojureScript's compiler (inspired by “On fast ClojureScript React templates”). When it is unable to determine type of the value it will emit interpretation call for the value and print a warning asking to annotate a value with either ^:inline or ^:interpret.

uix.core.alpha/defui does the same as html macro and additionally skips type checking arguments if a spec is provided.

(s/fdef button
  :args (s/cat :attrs map? :child string?)

(uix/defui button [{:keys [on-click]} child]
  [:button {:on-click on-click} child])

Lazy loading components

Loading React components on-demand as Closure modules. See code splitting guide and how lazy loading is used in React with Suspense: guide.

(uix/require-lazy '[uix.components :refer [ui-list]])

[:# {:fallback "Loading..."}
  (when show?

Server-side rendering (JVM)

See an example in

(uix.dom/render-to-string element) ;; see
(uix.dom/render-to-static-markup element) ;; see

;; Streaming HTML
(uix.dom/render-to-stream element {:on-chunk f}) ;; see
(uix.dom/render-to-static-stream element {:on-chunk f}) ;; see


  • Hiccup interpretation clojure -A:dev:benchmark:bench-front
  • SSR on JVM clojure -A:dev:benchmark:bench-ssr

Hiccup interpretation

react x 23202 ops/s, elapsed 431ms
uix-compile x 21834 ops/s, elapsed 458ms
uix-interpret x 14368 ops/s, elapsed 696ms
reagent-interpret x 7174 ops/s, elapsed 1394ms


lib test 1 test 2 test 3
rum 107.8 µs 3.6 ms 7.7 ms
uix 120.8 µs 3.8 ms 8.1 ms
uix streaming 115.7 µs 3.4 ms 7.6 ms
hiccup 205.7 µs 6.5 ms 16.6 ms

TodoMVC bundle size

lib size gzip
rum 254KB 70KB
reagent 269KB 74KB
uix 234KB 65KB


clojure -A:dev:test -m cljs.main -re node -m uix.compiler-test

Note: to ensure you're using the right Node.js version, you can use nvm and run nvm use once in the directory. Otherwise the Node.js version you use is in the .nvmrc file. See nvm repo for more documentation.

You can’t perform that action at this time.