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.
- 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:
Tip: Because Hiccup uses vectors to represent HTML trees, use lists to represent sequences. Mixing vector sequences with HTML vectors may confuse Hiccup.
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.
Styles can be added on the fly to elements via the
By default, integers are interpreted as pixels. If you want to use a different unit, use a string instead:
Sugar for the id and class attribute
Hiccup provides a convenient syntax for adding
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
: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:
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
test is true and
nil otherwise. Therefore, we can do:
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
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/htmlmacro. 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:
To force HTML generation directly, use
That’s it — the gist of Hiccup. Thanks for reading. Take a look at the resources below if you want to delve deeper and maybe my other stuff. If you have any questions, please feel free to send me an e-mail or leave a comment.