Introduction

Hiccup is a domain-specific language for generating HTML in Clojure. In other words, it turns Clojure into HTML. Let’s look at an example:

As you can see, it uses literal data structures — in fact, it’s just Clojure’s vectors containing keywords (representing tags) and maps (for HTML properties). The above example compiles down to:

…which is simple div with a single button which increments some atom counter. Everything is represented as a plain Clojure data-structure.

The advantages

No need to create separate files for templates. Hiccup is typically used in Reagent/re-frame projects, where views are just Clojure functions returning HTML (or functions returning functions). HTML represented as plain vectors which can be easily processed and generated using all the tools of the host language. This means that repetitive code can be abstracted away into functions and mechanically manipulated. A thin layer of abstraction allows improving HTML semantics while not being new enough to require re-learning.

The gist of it

Vectors and maps

If you’re building front-end using Reagent/re-frame, you will probably spend most of the time using Hiccup’s literals. In Hiccup, HTML nodes are represented as Clojure’s vectors. The first element of the vector is always a keyword (e.g. :div ) designating HTML tag. Immediately after the tag, we specify special options which act as a syntactic sugar (explained below). The second argument is an optional map of the tag’s attributes. We will specify here things such as inline styles, classes, event listeners, and so on. Lastly, we pass arguments to the element itself, such as a string for the label. Putting it all together, we have:

For example:

Tip: Because Hiccup uses vectors to represent HTML trees, use lists to represent sequences. Mixing vector sequences with HTML vectors may confuse Hiccup.

Constructor functions

Hiccup provides constructors for many of the standard HTML elements. Use them to remove some of the boilerplate. For example, instead of slightly verbose:

…we can do:

For a comprehensive listing, consult the API documentation.

Inline styling

Styles can be added on the fly to elements via the :style map:

By default, integers are interpreted as pixels. If you want to use a different unit, use a string instead: {:padding "50rem"} .

Sugar for the id and class attribute

Hiccup provides a convenient syntax for adding id and class attributes to an element. The following code:

…can be rewritten as:

The word after the # denotes the element’s ID, and each word after a dot corresponds to one of the element’s classes. The ID must always come first.

Tip: Specify permanent classes using sugar and dynamic ones via :class . Sometimes you will use a particular class only in certain conditions. For example, the class "active" may depend on the Boolean active? :

(Strings to :class are concatenated, so we need whitespace to separate classes). My suggestion is to specify classes that are static using sugar notation and leave everything else in the attribute map:

Conditional rendering

nil values are ignored. This means that we don’t have to worry about them slipping into our HTML. For example, Clojure’s function (when test & body) will return body if test is true and nil otherwise. Therefore, we can do:

If is-true? is false, the value of the expression will simply be ignored, and only element a will end up in the output.

Sugar for nested tags

To avoid repetitive nesting of HTML tags:

…you can use the > sugar:

Escape strings with h to avoid XSS

Hiccup concatenates strings without asking questions. Therefore, whenever you receive a string from unsafe sources (such as user form or foreign API) you should escape the string with hiccup.core/h :

Abstraction

One of the biggest advantages of using Hiccup is the ability to abstract away all the repetitiveness of manual HTML-writing. Instead of typing each li , we can use a loop:

Often, it’s a good idea to write a generator function for a commonly occurring element. For example:

…which yields a button with an internal counter variable. We can stack and nest those endlessly. However, as Eric Normand points out, there is one problem:

[..] because the Hiccup compiler doesn’t do a full examination of your code, it can’t compile everything. It inserts run time fallbacks for stuff it can’t handle at compile time which will interpret it at run time. So, for instance, if you’re calling a function that returns some Hiccup, it can’t compile that automatically. It has to wait till the function returns to know what it is. That is, unless . . . The fix: The way to get Hiccup to compile something is with the hiccup.core/html macro. That’s the macro that does the compilation and it will do it anywhere.

For most projects, this shouldn’t be a problem; however, a large codebase may lose some performance. To avoid this, we can do:

Rendering