Ornament

by Laurence Chen

Well done on the Compass app. I really like how fast it is (while retaining data consistently which is hugely undervalued these days). I’m not just being polite, I really like it.

by Malcolm Sparks

Before the Heart of Clojure event, one of the projects we spent a considerable amount of time preparing was Compass, and it’s open-source. This means that if you or your organization is planning a conference, you can use it.

When you decide to use Compass, besides importing the speaker and session data into the database, you’ll probably want to make some modifications to the frontend. That’s when you’ll quickly encounter an unfamiliar library: Ornament.

At first glance, the Ornament GitHub README is a bit lengthy, and you might be concerned about how difficult it is to learn. However, learning Ornament and using it for frontend development in the future is an excellent investment. Ornament requires a bit more time to learn because it’s a deep module. But because of this, it offers some competitive advantages that make it worth considering. Here are three key values:

  • Developer Ergonomics
  • Composability
  • High Performance

Developer Ergonomics

When you first see an introduction to Ornament, the easiest concept to grasp is that it’s a library that lets you write CSS directly within Clojure/ClojureScript.

When dealing with CSS, a common approach is to prepare several files dedicated to defining CSS and place the project’s custom CSS classes there. This means we typically have to switch back and forth between different cljs and css files during editing.

This back-and-forth problem was alleviated significantly with the rise of CSS utility classes like Tailwind and Tachyons. Developers could finally reference utility classes within a single cljs file. However, this method isn’t without limitations because sometimes we still want to do some customization or define custom CSS classes.

Ornament combines the flexibility of customization with the convenience of utility classes, allowing developers to handle everything within the cljs file. This way, we retain the flexibility of custom CSS while enjoying the streamlined experience of developing entirely within the cljs file.

Composability

There are two common uses for Ornament. The first is defining simple hiccup components, and the second is defining multi-layered hiccup components.

Consider a simple hiccup component:

(require '[lambdaisland.ornament :as o])

(o/defstyled freebies-link :a
  {:font-size "1rem"
   :color "#cff9cf"
   :text-decoration "underline"})

The defined component can be used with hiccup syntax:

;; Hiccup
[freebies-link {:href "/episodes/interceptors-concepts"} "Freebies"]

Which renders as: <a class="lambdaisland_episodes__freebies_link">Freebies</a>

Now, for a multi-layered hiccup component example:

(o/defstyled page-grid :div
  :relative :h-full :md:flex
  [:>.content :flex-1 :p-2 :md:p-10 :bg-gray-100]
  ([sidebar content]
   [:<>
    sidebar
    [:div.content
     content]]))

If you look closely, [:>.content :flex-1 :p-2 :md:p-10 :bg-gray-100] is no longer specifying the styles for :div itself, but rather for the child components under :div.

High Performance

Ornament was designed with the concept of css-in-js in mind, allowing users to define all CSS within components while writing Clojure or ClojureScript. This significantly reduces the amount of global CSS.

When using Clojure and Ornament, all CSS classes are generated during the build phase, which is intuitive. However, when using ClojureScript, should the CSS also be generated during the ClojureScript build phase, or should it still be generated by JavaScript? Ornament chooses to generate all required CSS during the ClojureScript build phase. This approach simplifies the build process, removes a lot of unnecessary styling definitions, and results in a smaller bundle size.

It originated from dissatisfaction and struggles

Ornament’s design and inspiration originated from frontend engineer Felipe Barros’ dissatisfaction and struggles with ClojureScript development, which led to extensive discussions. If you find Compass useful and fast, take some time to explore Ornament-—the time you invest will pay off.

Do you have any software development challenges or frustrations? Why not talk to us?