Reagent deep dive part 1: Hiccup and ratoms

Today I invite you to embark with me on the grand tour of Reagent, a ClojureScript library for building web pages. I will be encouraging you to try several small exercises on this page as we go. You can change the example code provided on this page to make it do other stuff. Let me know in the comments if you get stuck at all, or have any questions. This tour is going to get down into the nitty gritty of everything UI, including the kitchen sink. I will do my best to keep things interesting.


To get good at finishing, you first need to get good at starting. -- Unknown

To use Reagent in this page we require reagent.core in our namespace declaration. Typically there will be a call to reagent/render-component to start the rendering process.

(ns my.reagent-examples
    [reagent.core :as reagent]

(ns my.reagent-examples
  (:require [reagent.core :as reagent]))

(when-let [element (js/document.getElementById "app")]
  (reagent/render-component [component] element)))

Reagent works by rendering HTML to an existing element in the page. So a Reagent app consists of a bare bones HTML page (index.html) which contains an element suitable for replacement. Typically this will be something like
<div id="app"></div>

To start the rendering process we call reagent/render-component with a component and the target div.

That's it for setup, we are ready to rock and roll!

A Reagent component is a function

True success has more components than one sentence or idea can contain. -- Zig Ziglar

The central abstraction Reagent provides for building views is the component. A component is a function that produces some HTML, and components can be nested to build a full application. A Reagent component is a function that returns hiccup. Hiccup is a concise way to express HTML as data. In HTML you express a paragraph with the p tag:

<p>Hello world</p>

The hiccup equivalent is:

[:p "Hello world"]

Let's write our first component.

Example A: The "hello world" Reagent component

(defn greetings []
  [:p "Hello world"])

To create a component we define a function that returns a vector where the first element of the vector is a HTML tag keyword.

Exercise: Change Example A to return a heading <h1> tag with your name in it. You can edit the examples in this page (thanks to KLIPSE). Simply modify the code in the example boxes to complete the exercises.

More about hiccup

I think hiccup cures were really invented for the amusement of the patient's friends. -- Bill Watterson

HTML tags can contain attributes. For instance an image source is expressed as an attribute:
<img src="">
In hiccup, we express attributes as an optional map as the second element in a hiccup vector:

Example B: An image tag with a source attribute

 {:src ""}]

Pop quiz: What is the hiccup equivalent of
<a href="">Reagent</a>?

You can nest elements in the same way that you would nest HTML tags:

 [:div "Hello world"]]

Tip: [[:div] [:div]] is not a valid Reagent component. The first element of a Reagent component must be a tag identifier or component. If you want to return 2 divs, you need to wrap them in a parent div:


Just like other attributes, you can specify handler attributes such as onClick. The Clojure kebab-style :on-click is automatically translated to camelCase onClick for convenience.

Example C: A clickable button

  (fn [e]
    (js/alert "You pressed the button!"))}
 "Do not press"]

Styles attributes are expressed as a map.

<p style="color: red; background: lightblue;">Such style!</p>

is written in hiccup as:

Example D: Inline styles

 {:style {:color "white"
          :background "darkblue"}}
  "Such style!"]

There is a shorthand for expressing class and id.

is equivalent to:
 {:id "my-id"
  :className "my-class1 my-class2"}]

Generally attributes map to exactly what you would expect from HTML... but it is important to understand that onclick (no hypen or camelCase) will not work. Attributes are mapped according to the React specification of attributes. If you are having trouble describing an attribute, check the React reference page to make sure you are using the appropriate name and hyphenation. That page lists all the possible attributes you can use.

There is also an escape hatch dangerouslySetHtml. You won't need it anytime soon, but it's good to know that it exists. If there is a mapping not covered by React, or you need to render a HTML template, you can use the escape hatch to write HTML from text instead of hiccup.

Let's use our knowledge to construct a more complicated component using SVG HTML elements. All of this is regular HTML.

Example E: A more complicated component using SVG tags

(defn concentric-circles []
  [:svg {:style {:border "1px solid"
                 :background "white"
                 :width "150px"
                 :height "150px"}}
   [:circle {:r 50, :cx 75, :cy 75, :fill "green"}]
   [:circle {:r 25, :cx 75, :cy 75, :fill "blue"}]
   [:path {:stroke-width 12
           :stroke "white"
           :fill "none"
           :d "M 30,40 C 100,40 50,110 120,110"}]])

As you can see we created an SVG element containing two concentric circles, and a path stroke through them. One important thing to point out here is that our function is returning a data structure.

Exercise: Complete the Lambda symbol (λ) by adding a diagonal down path.
You can find hints in the SVG Reference.

Naturally you can also do all the boring form input related stuff too *yawn*.

Example F: A tiny form for form's sake

 [:h3 "Greetings human"]
   (fn [e]
     (.preventDefault e)
       (str "You said: " (.. e -target -elements -message -value))))}
   "Say something:"
    {:name "message"
     :type "text"
     :default-value "Hello"}]]
  [:input {:type "submit"}]]]

This is all just regular HTML represented in hiccup syntax.

Exercise: Add a select options list to this form containing your three favorite words.
Hint: The HTML would look like <select><option>Donut</option></select>

Nesting components

What is a fish without a river? What is a bird without a tree to nest in? -- Jay Inslee

A Reagent component is a function, so you can call it directly and it will return a result:


But, for reasons that will become apparent, we do not call components directly. Instead we nest components, in the same way that we nest hiccup forms:

(defn greet2 [message]
  [:div [greetings]])

The only visible difference between calling a component and nesting a component is that we surround it in square braces instead of round parenthesis.

Example G: An SVG component that nests another component

(defn many-circles []
    [:svg {:style {:border "1px solid"
                   :background "white"
                   :width "600px"
                   :height "600px"}}]
    (for [i (range 12)]
       {:transform (str
                     "translate(300,300) "
                     "rotate(" (* i 30) ") "

Here we make use of our previous component. We put 12 instances of concentric-circle into an SVG.

Exercise: Redefine concentric-circle to return a g element instead of an svg. Add an argument to take the rotation as an input. Don't forget to pass i to concentric-circles. Refactoring and composing components should feel very familiar, it's the same thing we do with any other function. Functions are a convenient way to organize view modularity to suit your tastes.

But why do we use braces instead of parenthesis? You ask a good question... The reason is efficiency. The React philosophy is that views are functions of their inputs, and that view need only be re-rendered when their inputs change. If the input arguments of a function do not change, the result is the same, so there is no point calling it. We only need to call a view component if the inputs it relies on have changed.

If our components called sub components directly, it would force them to always compute a result. We don't want that. Instead we leave the task of calling the component up to Reagent. Reagent will figure out when it needs to evaluate a component. Our job is strictly to specify the structure of the view, which we do by returning a vector. The vector we return contains the sub components, but is not forcing evaluation of them.

Tip: Remember to use [component argument] instead of (component argument) when nesting components.

Doing stuff!

Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do. -- Pele

We want our webpage to respond to user interaction and change. We need two things to achieve change:
  1. Inputs to our components.
  2. Something to watch and react to.
Component inputs are just regular function inputs. The new thing that Reagent introduces is the thing to watch and react to; the reagent/atom.

Reagent atoms behave very much like a regular Clojure atom. You change them with swap! or reset! and you get their value by deref @my-atom. The special thing about a reagent/atom is that all components that deref it will be re-rendered whenever the value held by the reagent/atom changes.

Example H: A counter component that re-renders on change

(def c
  (reagent/atom 1))

(defn counter []
   [:div "Current counter value: " @c]
    {:disabled (>= @c 4)
     (fn clicked [e]
       (swap! c inc))}
    {:disabled (<= @c 1)
     (fn clicked [e]
       (swap! c dec))}
   (into [:div] (repeat @c [concentric-circles]))])

When we click the button, the value of counter is incremented, causing the counter-component to re-render. We don't have to do anything special to get this behavior. Our function derefs the counter, so Reagent knows that it needs to re-render this component whenever counter changes.

Tip: Be careful to make sure you are using a reagent/atom, not a regular atom... A regular atom will not cause components to re-render.

We can also write conditional code.

Example I: Rendering different HTML elements with conditional logic

(let [show? (reagent/atom false)]
  (fn waldo []
     (if @show?
        [:h3 "You found me!"]
         {:src ""
          :style {:height "320px"}}]]
        [:h3 "Where are you now?"]
         {:src ""
          :style {:height "320px"}}]])
       (fn [e]
         (swap! show? not))}
      (if @show? "reset" "search")]]))

Data is very flexible. One of the big wins here is that we can construct data with conditionals. We don't need an explicit template, we have all the power of Clojure to build and manipulate data.


A positive attitude causes a chain reaction of positive thoughts, events and outcomes. It is a catalyst and it sparks extraordinary results. -- Wade Boggs

Reactions are really quite amazing. Reactions define a reagent/atom like thing as an expression. It will fire updates when any reactive value it depends on changes.

Example J: Sorting as a reaction

(def rolls (reagent/atom [1 2 3 4]))
(def sorted-rolls (reagent.ratom/reaction (sort @rolls)))

(defn sorted-d20 []
   [:button {:on-click (fn [e] (swap! rolls conj (rand-int 20)))} "Roll!"]
   [:p (pr-str @sorted-rolls)]
   [:p (pr-str (reverse @sorted-rolls))]])

Here we use a reaction that depends on rolls, which calculates a new value; the sorted rolls. We make use of sorted-rolls twice, but the sort is only computed once each time rolls changes. Reactions can depend on multiple things. They are a useful mechanism for defining a data flow efficiently. They are a convenient way to define data transforms that rely on multiple sources, or that will be used in multiple contexts.

Reactions are elegant to use in small quantities. The drawback of using reactions everywhere is that too many of them can become an unsightly mess of boilerplate. My rule of thumb is to use them in moderation where there is a clear performance or expressive advantage.

This leads us to a somewhat abstract consideration. If we structure our application with a single large global reagent/atom, it may be updated from multiple sources. We wouldn't want every component updated whenever any unrelated change occurred.

Reagent offers several answers to the question of how to organize code to react to application state. Reagent has reactions, cursors, and track. I'll not cover those here beyond our discussion of reactions, because I see them as situationally useful but not generally applicable.

For handling large application state, a well thought out and popular approach is to use re-frame. You should definitely read the re-frame documentation. It provides an in depth treatment of data flow in a reactive application.

The last thing I will say on this topic is that you can go a long way with the humble reagent/atom. So get building and don't over think it.


Good night, good night! Parting is such sweet sorrow, that I shall say good night till it be morrow. -- William Shakespeare

We have reached the first stop of our tour! We know how to build Reagent components and effect change to our application. We learnt that Reagent's fundamental abstraction is a view component. A view component is a function that returns HTML as hiccup. The mechanism for observing and effecting change is the reagent/atom.

In part 2 of the tour we shall examine the lifecycle of a Reagent component, and see how that enables us to build a 3D Sierpinski Gasket.


  1. If only the minutes I spend on the web were as half as productive and fun as those I've just spent here... Thanks a lot for taking the time to share this with us!

    1. Hi Samuel! Thank you very much for your kind feedback. I really appreciate the encouragement. :)

  2. Thanks very much for putting this together! Very much appreciated. I look forward to part 2.

    1. Hi Nando,

      You are most welcome! I had a lot of fun writing it.
      Part 2 is available now
      Part 3 should be out on Monday (or Tuesday) :)

  3. just read part 1 and 2 in the reverse order but this is one of the best intros ive seen to reagent thanks for putting this together


    1. Thank you for the kind words, very much appreciated :)

  4. <3 love series.
    Thanks so much!

  5. Great post! Moving on to the rest of the series.

    One minor point: shouldn't `dangerouslySetHtml` be `dangerouslySetInnerHTML`?

    1. Yes you are correct. Thanks for the correction. 😃

  6. This comment has been removed by the author.

  7. If you keep your entire application state in a single reagent atom, do I understand that only using reactions in components would mean that you can still avoid re-rendering each component unless its particular area of interest in that application state changed, as reflected in the reaction? In other words, all of the reactions would still process when the single app state changed, but their resulting values in many cases would not change, and therefore the re-rendering would not happen. Is that about right?

  8. Your blog has given me that thing which I never expect to get from all over the websites. Nice post guys!

    Web Designer

  9. Enthusiastic words written in this blog helped me to enhance my skills as well as helped me to know how I can help myself on my own. I am really glad to come at this platform.Character Design

  10. Now day, everything is going to find a new but well settled and successful stream for their career. When I came to this blog, I really impressed by all the knowledge points mentioned here. Thank you for this assistance.Taxi Charter Service

  11. Yes! Excellent material


  12. نحن افضل شركة تنظيف بالمملكة العربية السعودية وهذه شهادة من جميع عملائنا الاعزاء فتواصلوا معنا فشركة الحورس تعمل دائما من اجل تلبية كافة المتطلبات و الاحتياجات .
    شركة تنظيف بالباحه

  13. Thank you a lot for such introduction!
    I thought that VueJS is magic. But no, seems magic begins with Reagent :)

  14. These are really well done tutorials, thanks so much!

  15. The quality of your articles and contents is great. array

  16. تعد شركة ركن الامانة (0505561372) من الشركات المتخصصة فى اعمال التنظيف و النقل و المكافحة بالمنطقة الجنوبية فى المملكة العربية السعودية فهى تقدم خدمات متميزة وعلى اعلى مستوى من الخبرة و التقنية بالاعتماد على عمال مدربين ومتميزين فى عمالهم ونقدم خدمات باقل الاسعار التى تناسب جميع عملائنا الكرام فتواصلوا معنا
    شركة تنظيف بخميس مشيط
    شركة تنظيف منازل بخميس مشيط
    شركة تنظيف كنب بخميس مشيط
    شركة عزل اسطح بخميس مشيط
    شركة مكافحة حشرات بخميس مشيط

  17. I never ever read such type of info before this was really incredible.
    tutorial on c++

  18. Professionally written blogs are rare to find, however I appreciate all the points mentioned here. I also want to include some other writing skills which everyone must aware of.
    CAD Drawing

  19. Graceful written content on this blog is really useful for everyone same as I got to know. Difficult to locate relevant and useful informative blog as I found this one to get more knowledge but this is really a nice one.
    Line Sticker

  20. Really nice blog post.provided a helpful information.I hope that you will post more updates like this Ruby on Rails Online Course Bangalore

  21. Sometime few educational blogs become very helpful while getting relevant and new information related to your targeted area. As I found this blog and appreciate the information delivered to my database.
    responsive web design services

  22. This blog is really helpful for my database. It enhanced the area of my thoughts and pushed me beyond the boundaries. Work ethic of every point is different and represent a new way to improve myself.

  23. A blog must be connected to the person in need. It is really important to understand the actual feel of such necessity and the essence of objective behind it. Author must give proper time to understand every topic before writing it.

  24. Graceful written content on this blog is really useful for everyone same as I got to know. Difficult to locate relevant and useful informative blog as I found this one to get more knowledge but this is really a nice one.
    Web Design

  25. I am grateful to you on the grounds that your article is exceptionally useful for me to continue with my exploration in same region. Your cited illustrations are all that much significant to my exploration field.This is extraordinary! It really exhibits to me where to broaden my online diary
    เสื้อ polo

  26. An author must have a vast knowledge of vocabulary. The dictionary of a writer must be full of new english vocabulary to make their work more attractive. Use of new words makes their work more valuable and graceful.
    HPE ProLiant DL80 Gen9

  27. This is really nice to read content of this blog. A is very extensive and vast knowledgeable platform has been given by this blog. I really appreciate this blog to has such kind of educational knowledge.
    โปรโมชั่น ตั๋วเครื่องบิน

  28. Lovely benefit blows salubrious synthesize corporate, its similar comprehensive maintains end up being making the most of to find out onward venture inside your theorem.. Lovely hawk. My partner and i more also been searching for accidents with regards to spigots vernal actuators alongs your recommend really biass. Confesss some sort of numerous pertaining to putting up this.
    คูปอง Officemate

  29. My partner and i get also been difficult to complete my own appliance to get a felon in addition My business is touchings operating unfamiliar person of several. As well as bless for your weblog, My partner and i marvel where to office well known poise decide Australia. My partner and i quite withstand the actual personify illusion pertaining to my own standing!
    Knob DIN 69872 Pull Studs

  30. Common bribes ineluctables homogeneous level to do something. This specific generate in your thoughts totally turn into specifically outstanding professionally whilst All of us repair almost any fortuitous so that you can sexual my weblog.
    2 Flute Endmills Ball End

  31. Your blog specializing in going over the actual without a doubt contemptuous with on their own released coerces. Your blog aid is usually synchronize towards the fit swift. My partner and i from the weblog exuviate to supply. Clues some sort of numerous pertaining to expressing.
    Solid Carbide Split-End Engraving Tools