Top Related Projects
A ClojureScript framework for building user interfaces, leveraging React
Fast library for rendering HTML in Clojure
Simple, decomplected, isomorphic HTML UI library for Clojure and ClojureScript
A library for development of single-page full-stack web applications in clj/cljs
Simple and powerful tool for building web apps out of highly composable elements in ClojureScript.
Quick Overview
Reagent is a minimalistic ClojureScript interface to React.js, designed to make it easy to create efficient React components using ClojureScript. It provides a simple and idiomatic way to define React components and manage application state, leveraging the power of ClojureScript's functional programming paradigm.
Pros
- Simple and intuitive API, making it easy for ClojureScript developers to create React applications
- Excellent performance due to efficient rendering and state management
- Seamless integration with existing React ecosystem and libraries
- Encourages functional programming patterns, leading to more maintainable code
Cons
- Limited documentation compared to some other React wrappers
- Smaller community compared to JavaScript-based React libraries
- Learning curve for developers not familiar with ClojureScript or functional programming
- May require additional setup and tooling for optimal development experience
Code Examples
- Creating a simple component:
(ns example.core
(:require [reagent.core :as r]))
(defn hello-world []
[:div
[:h1 "Hello, World!"]
[:p "Welcome to Reagent"]])
(r/render [hello-world]
(js/document.getElementById "app"))
- Managing component state:
(defn counter []
(let [count (r/atom 0)]
(fn []
[:div
[:p "Count: " @count]
[:button {:on-click #(swap! count inc)} "Increment"]])))
- Using React hooks with Reagent:
(ns example.hooks
(:require [reagent.core :as r]
[reagent.dom :as rdom]))
(defn use-counter [initial-count]
(let [count (r/atom initial-count)]
{:count @count
:increment #(swap! count inc)
:decrement #(swap! count dec)}))
(defn counter-component []
(let [{:keys [count increment decrement]} (use-counter 0)]
[:div
[:p "Count: " count]
[:button {:on-click increment} "Increment"]
[:button {:on-click decrement} "Decrement"]]))
(rdom/render [counter-component]
(js/document.getElementById "app"))
Getting Started
To get started with Reagent, follow these steps:
-
Add Reagent to your project dependencies:
[reagent "1.1.1"]
-
Require Reagent in your namespace:
(ns your-app.core (:require [reagent.core :as r] [reagent.dom :as rdom]))
-
Create a simple component and render it:
(defn hello-world [] [:h1 "Hello, World!"]) (rdom/render [hello-world] (js/document.getElementById "app"))
-
Run your ClojureScript build process and open the HTML file in a browser to see your Reagent application in action.
Competitor Comparisons
A ClojureScript framework for building user interfaces, leveraging React
Pros of re-frame
- Provides a more structured architecture with clear separation of concerns
- Offers built-in effects and coeffects system for side-effect management
- Includes debugging tools and time-travel debugging capabilities
Cons of re-frame
- Steeper learning curve due to additional concepts and complexity
- May be overkill for smaller applications or simpler use cases
- Requires more boilerplate code compared to Reagent's simplicity
Code Comparison
Reagent example:
(defn counter []
(let [count (r/atom 0)]
(fn []
[:div
"Count: " @count
[:button {:on-click #(swap! count inc)} "Increment"]])))
re-frame example:
(rf/reg-event-db :increment (fn [db _] (update db :count inc)))
(rf/reg-sub :count (fn [db _] (:count db)))
(defn counter []
(let [count (rf/subscribe [:count])]
[:div
"Count: " @count
[:button {:on-click #(rf/dispatch [:increment])} "Increment"]]))
Both Reagent and re-frame are popular libraries for building user interfaces in ClojureScript. Reagent provides a simple and lightweight approach to building reactive components, while re-frame offers a more comprehensive framework with additional features for state management and application architecture. The choice between the two depends on the project's complexity and specific requirements.
Fast library for rendering HTML in Clojure
Pros of Hiccup
- Simpler and more lightweight, focusing solely on HTML generation
- More flexible for non-React use cases, such as server-side rendering
- Easier to learn and use for developers not familiar with React concepts
Cons of Hiccup
- Lacks built-in state management and component lifecycle features
- Doesn't provide automatic re-rendering on data changes
- May require more boilerplate code for complex UI interactions
Code Comparison
Hiccup:
(defn my-component [name]
[:div
[:h1 (str "Hello, " name "!")]
[:p "Welcome to Hiccup."]])
Reagent:
(defn my-component [name]
(let [count (reagent/atom 0)]
(fn []
[:div
[:h1 (str "Hello, " name "!")]
[:p "Welcome to Reagent."]
[:p "Clicks: " @count]
[:button {:on-click #(swap! count inc)} "Click me"]])))
The Hiccup example shows a simple component for generating HTML, while the Reagent example demonstrates reactive state management and event handling capabilities built into the library.
Simple, decomplected, isomorphic HTML UI library for Clojure and ClojureScript
Pros of Rum
- Simpler API with fewer concepts to learn
- Better performance for large, complex UIs
- More flexible, allowing direct manipulation of the virtual DOM
Cons of Rum
- Smaller community and ecosystem compared to Reagent
- Less integration with other ClojureScript libraries
- Steeper learning curve for beginners due to lower-level API
Code Comparison
Rum example:
(rum/defc hello [name]
[:div "Hello, " name "!"])
(rum/mount (hello "World")
(. js/document (getElementById "app")))
Reagent example:
(defn hello [name]
[:div "Hello, " name "!"])
(reagent/render [hello "World"]
(.getElementById js/document "app"))
Both Rum and Reagent are popular ClojureScript libraries for building user interfaces. Rum offers a simpler API and potentially better performance for complex UIs, while Reagent has a larger ecosystem and is generally easier for beginners to pick up. The code comparison shows that both libraries have similar syntax for defining components, with minor differences in mounting/rendering.
A library for development of single-page full-stack web applications in clj/cljs
Pros of Fulcro
- Comprehensive full-stack framework with built-in state management
- Advanced query language for efficient data fetching
- Integrated routing and component-based architecture
Cons of Fulcro
- Steeper learning curve due to its complexity
- More opinionated and less flexible than Reagent
- Larger codebase and potential overhead for smaller projects
Code Comparison
Reagent component:
(defn hello-world []
[:div
[:h1 "Hello, World!"]
[:p "Welcome to Reagent"]])
Fulcro component:
(defsc HelloWorld [this props]
{:query []
:ident (fn [] [:component/id :hello-world])}
(div
(h1 "Hello, World!")
(p "Welcome to Fulcro")))
Summary
Reagent is a lightweight, flexible library for building React components in ClojureScript, while Fulcro is a comprehensive full-stack framework. Reagent offers simplicity and ease of use, making it ideal for smaller projects or developers new to ClojureScript. Fulcro provides a more structured approach with built-in state management, routing, and advanced querying capabilities, suitable for larger, more complex applications. The choice between the two depends on project requirements, team expertise, and desired level of abstraction.
Simple and powerful tool for building web apps out of highly composable elements in ClojureScript.
Pros of Hoplon
- Unique approach using "cells" for reactive programming
- Integrates HTML, CSS, and ClojureScript in a single file
- Supports isomorphic web applications (server-side rendering)
Cons of Hoplon
- Steeper learning curve due to its unique concepts
- Smaller community and ecosystem compared to Reagent
- Less frequent updates and maintenance
Code Comparison
Hoplon:
(page "index.html"
(:require [hoplon.core :as h])
(h/html
(h/body
(h/h1 "Hello, Hoplon!"))))
Reagent:
(ns example.core
(:require [reagent.core :as r]))
(defn hello-world []
[:h1 "Hello, Reagent!"])
(r/render [hello-world]
(js/document.getElementById "app"))
Key Differences
- Hoplon uses a more integrated approach, combining HTML, CSS, and ClojureScript
- Reagent follows a more traditional React-like component structure
- Hoplon's reactive system is based on "cells," while Reagent uses Reagent atoms
- Reagent has a larger community and more frequent updates
- Hoplon offers built-in support for isomorphic applications, while Reagent requires additional setup
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME

A simple ClojureScript interface to React.
Reagent provides a way to write efficient React components using (almost) nothing but plain ClojureScript functions.
- Detailed intro with live examples
- News
- Documentation, latest release
- Documentation, next release: API docs, Tutorials and FAQ
- Community discussion and support channels
- #reagent channel in Clojure Slack
- Commercial video material
- Learn Reagent Free, Learn Reagent Pro (Affiliate link, $30 discount)
- Learn Re-frame Free, Learn Re-frame Pro (Affiliate link, $30 discount)
- purelyfunctional.tv
- Lambda Island Videos
Usage
To create a new Reagent project using Leiningen template simply run:
lein new reagent myproject
If you wish to only create the assets for ClojureScript without a Clojure backend then do the following instead:
lein new reagent-frontend myproject
This will setup a new Reagent project with some reasonable defaults, see here for more details.
To use Reagent in an existing project you add this to your dependencies in project.clj
:
And provide React using either npm (when using e.g. Shadow-cljs)
npm i react react-dom@18.3.1 react@18.3.1
or by adding Cljsjs React packages to your project:
[cljsjs/react "18.3.1-1"]
[cljsjs/react-dom "18.3.1-1"]
Note: Reagent is tested against React 18, using the compatibility mode (i.e.,
not using createRoot
/ concurrent mode), but should be compatible with other
versions. It is not compatible with React 19
Reagent isn't tied to only React-dom but should work with other renderers also.
Examples
Reagent uses Hiccup-like markup instead of JSX. It looks like this:
(defn some-component []
[:div
[:h3 "I am a component!"]
[:p.someclass
"I have " [:strong "bold"]
[:span {:style {:color "red"}} " and red"]
" text."]])
Since version 0.8: The
:class
attribute also supports collections of classes, and nil values are removed:[:div {:class ["a-class" (when active? "active") "b-class"]}]
You can use one component inside another:
(defn calling-component []
[:div "Parent component"
[some-component]])
And pass properties from one component to another:
(defn child [name]
[:p "Hi, I am " name])
(defn parent []
[child "Foo Bar"])
You mount the component into the DOM like this:
(defn mount-it []
(rd/render [parent] (.-body js/document)))
assuming we have imported Reagent like this:
(ns example
(:require [reagent.core :as r]
[reagent.dom :as rd]))
State is handled using Reagent's version of atom
, like this:
(defonce click-count (r/atom 0))
(defn state-ful-with-atom []
[:div {:on-click #(swap! click-count inc)}
"I have been clicked " @click-count " times."])
Any component that dereferences a reagent.core/atom
will be automatically re-rendered.
If you want to do some setting up when the component is first created, the component function can return a new function that will be called to do the actual rendering:
(defn timer-component []
(let [seconds-elapsed (r/atom 0)]
(fn []
(js/setTimeout #(swap! seconds-elapsed inc) 1000)
[:div
"Seconds Elapsed: " @seconds-elapsed])))
This way you can avoid using React's lifecycle callbacks like getInitialState
and componentWillMount
most of the time.
But you can still use them if you want to, either using reagent.core/create-class
or by attaching meta-data to a component function:
(defonce my-html (r/atom ""))
(defn plain-component []
[:p "My html is " @my-html])
(def component-with-callback
(with-meta plain-component
{:component-did-mount
(fn [this]
(reset! my-html (.-innerHTML (rd/dom-node this))))}))
See the examples directory for more examples.
Performance
React is pretty darn fast, and so is Reagent. It should even be faster than plain old javascript React a lot of the time, since ClojureScript allows us to skip a lot of unnecessary rendering (through judicious use of React's shouldComponentUpdate
).
The ClojureScript overhead is kept down, thanks to lots of caching.
Code size is a little bigger than React.js, but still quite small. The todomvc example clocks in at roughly 79K gzipped, using advanced compilation.
About
The idea and some of the code for making components atom-like comes from pump. The reactive-atom idea (and some code) comes from reflex.
The license is MIT.
Top Related Projects
A ClojureScript framework for building user interfaces, leveraging React
Fast library for rendering HTML in Clojure
Simple, decomplected, isomorphic HTML UI library for Clojure and ClojureScript
A library for development of single-page full-stack web applications in clj/cljs
Simple and powerful tool for building web apps out of highly composable elements in ClojureScript.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot