# Reagent: A Minimalistic ClojureScript Interface to React

> Reagent is a ClojureScript library that wraps React using Hiccup-style syntax and a reactive atom model. It lets engineers build React components as plain ClojureScript functions, with automatic re-rendering driven by atom dereferences rather than explicit setState calls.

**reagent-project/reagent** — A minimalistic ClojureScript interface to React.js

- Repository: https://github.com/reagent-project/reagent
- Website: http://reagent-project.github.io/
- Stars: 4,889 · Forks: 413
- Language: Clojure
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/reagent-project-reagent

## Writing React Components as ClojureScript Functions

Reagent targets ClojureScript developers who need to build React user interfaces without writing JSX or JavaScript class components. The project's own description states it provides 'a way to write efficient React components using (almost) nothing but plain ClojureScript functions.'

This matters because the ClojureScript toolchain, particularly Shadow-cljs and Figwheel, compiles ClojureScript to JavaScript, but the developer still needs a way to describe the DOM. Reagent's answer is Hiccup syntax: nested ClojureScript vectors where the first element is a keyword naming the HTML tag, the second is an optional map of attributes, and the remaining elements are children. This is idiomatic ClojureScript and integrates naturally with ClojureScript's immutable data structures, which is a meaningful difference from calling React.createElement or compiling JSX.

## Hiccup Syntax, Reactive Atoms, and the Re-render Trigger

A Reagent component is a ClojureScript function that returns a Hiccup vector. The README shows a basic example:

```clj
(defn some-component []
  [:div
   [:h3 "I am a component!"]
   [:p.someclass
    "I have " [:strong "bold"]
    [:span {:style {:color "red"}} " and red"]
    " text."]])
```

State is managed through reagent.core/atom, which behaves like a standard ClojureScript atom but also registers components that dereference it as dependents. When the atom value changes, Reagent re-renders only the components that read it. The README shows the pattern:

```clj
(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."])
```

The deref (@) inside the function body is the signal. Reagent tracks it at call time and establishes the re-render dependency automatically. This avoids the need to declare dependencies explicitly in a hook dependency array, which is how React's useState and useEffect work.

Components can compose naturally. One component's output vector can include another component as a child:

```clj
(defn calling-component []
  [:div "Parent component"
   [some-component]])
```

Using square brackets to embed a child component, rather than parentheses, is the Reagent convention that distinguishes React component instantiation from a plain function call.

## Adding Reagent to a Project and Mounting a First Component

The README instructs adding Reagent as a Clojars dependency in project.clj. It shows installing React via npm when using Shadow-cljs:

```
npm i react@19.2.3 react-dom@19.2.3
```

Once the dependencies are installed, a component is mounted to the DOM with reagent.dom/render:

```clj
(ns example
  (:require [reagent.core :as r]
            [reagent.dom :as rd]))

(defn mount-it []
  (rd/render [parent] (.-body js/document)))
```

For components that need setup on first creation, Reagent supports a function-returning-function pattern. The outer function runs once on create, and the inner function is called on each render:

```clj
(defn timer-component []
  (let [seconds-elapsed (r/atom 0)]
    (fn []
      (js/setTimeout #(swap! seconds-elapsed inc) 1000)
      [:div
       "Seconds Elapsed: " @seconds-elapsed])))
```

This pattern replaces React lifecycle methods like getInitialState and componentWillMount for most cases. The README notes that React lifecycle callbacks are still available through reagent.core/create-class or by attaching metadata to a component function when direct lifecycle access is needed.

## Performance Model and the Role of ClojureScript Immutable Data

The README states that Reagent skips unnecessary renders 'through judicious use of React's shouldComponentUpdate.' ClojureScript's persistent data structures support cheap equality checks by identity, which lets Reagent determine that a component's props have not changed without a deep comparison. For components receiving the same atom reference with the same value, the render is skipped.

The README also notes that the ToDoMVC example compiles to roughly 79 KB gzipped using advanced compilation. That figure is from the repository's own example and reflects the overhead of ClojureScript's standard library plus Reagent's React wrapper layer. A production ClojureScript project using Reagent will be larger than a comparable JavaScript React project, because the ClojureScript compiler output includes the standard library regardless of tree-shaking. Teams sensitive to initial load size should measure their specific build.

## Where Reagent Falls Short

Reagent is a React wrapper, not a state management framework. For applications with complex event flows across many components, the reactive atom model becomes hard to track. The README acknowledges this by pointing to re-frame, a separate library built on Reagent that adds an event bus, subscriptions, and effects. Reagent alone is not sufficient for large applications with shared mutable state across many independent component trees.

Reagent's rendering is tied to the React version it targets. The package.json specifies react@19.2.3 and react-dom@19.2.3 as dependencies. Upgrading React independently of Reagent may break rendering because Reagent's internal hooks into React's reconciler are version-specific. The README notes that minor or patch versions of React should be safe to use, but major version upgrades have historically required Reagent releases to track them.

The repository has no GitHub releases, so version tracking depends on Clojars. The last push to the repository was on 2026-08-19.

## Reagent vs Re-frame: the Same Rendering Layer, Different Scope

Re-frame is the most common companion framework for Reagent. It uses Reagent's reactive atoms and component model as its rendering layer but adds an application-level event system: dispatched events flow through a handler, which updates a central application database atom, which re-frame subscriptions watch. Components read from subscriptions rather than directly from atoms.

The practical difference is scope. Reagent is appropriate when components manage their own local state and few pieces of state need to be shared. Re-frame is appropriate when event ordering, side effects, and global application state need a structured approach. The README lists re-frame alongside other commercial video learning resources, which signals that the ecosystem treats the two as complementary rather than competing.

Alternatives outside the ClojureScript ecosystem include Solid.js, which uses a similar reactive signal model without ClojureScript's syntax, and plain React with hooks. Neither replaces Reagent for teams committed to the ClojureScript toolchain.

## Maintenance Status and License

The last push to the repository was on 2026-08-19. The repository has no GitHub releases; versions are published to Clojars only. The CHANGELOG.md in the repository records version history.

The license is MIT. There are no restrictions on use in commercial or closed-source applications. The project has a SECURITY.md, a CONTRIBUTING.md, and a ROADMAP.md in the repository root, which signals that the maintainers have considered long-term governance.

The package.json shows node@24 and npm@11 as the required Node.js toolchain for the development environment, and shadow-cljs@3.2.1 as the build tool. Teams using older Node.js versions need to upgrade before working on Reagent's own source.

## Conclusion

Reagent fits ClojureScript projects that need a React integration without JSX or JavaScript component classes. Its reactive atom model is the smallest possible state mechanism that triggers re-renders, which makes it a good fit for smaller applications or as a foundation for state management libraries built on top of it. Projects that need full application-level state management from day one should evaluate re-frame, which the README lists as a companion framework. Teams using newer React features like concurrent rendering should check the Reagent changelog and React compatibility notes before adopting, since Reagent's rendering is coupled to a specific React API surface that changes across major React versions. The Clojars page for reagent lists the version required for the current React 19 line.

## FAQ

### How does Reagent's reactive atom differ from React's useState?

Reagent's r/atom is a ClojureScript atom that also tracks which components have dereferenced it. When its value changes, Reagent re-renders those components automatically. Unlike React's useState, there is no dependency array to declare and no setter function to call; the component function is re-run whenever an atom it reads changes.

### Does Reagent work with React 19?

The repository's package.json specifies react@19.2.3 and react-dom@19.2.3 as development dependencies. The README states that minor or patch versions of React beyond what is pinned should be safe to use.

### Can Reagent components use React lifecycle methods?

Yes. Reagent supports React lifecycle callbacks through reagent.core/create-class or by attaching metadata to a component function using with-meta. The README notes that the function-returning-function pattern covers most lifecycle cases without requiring explicit callbacks.

## Sources

- [Issues](https://github.com/reagent-project/reagent/issues)
- [License: MIT](https://github.com/reagent-project/reagent/blob/master/LICENSE)
- [Project website](http://reagent-project.github.io/)
- [README](https://github.com/reagent-project/reagent/blob/master/README.md)
- [reagent-project/reagent on GitHub](https://github.com/reagent-project/reagent)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/reagent-project-reagent
