Clojure bites - Rendering HTML

by FPSD — Thu 08 June 2023


Overview

There are many ways to produce HTML in Clojure, from template engines to data oriented DSLs and React wrappers. Each one has it own use cases, benefits and downsides so there is no one solution that fits all problems.

In this post we will have a look at selmer, a library that offers a well known approach for HTML templating, by the prolific Dmitri Sotnikov (AKA Yogthos).

Selmer

Since the beginning of time, template engines have ruled the world of web development, in a form or another. That is how the majestic PHP has come to life, and it is still out there and kicking.

Other notable mentions in the same space are Jinja for Python, Erc for Ruby, Mustache/Handlebars for JS, and probably many, many more for all of the available languages anyone can think of.

In Clojure world selmer is a very nice library that will look familiar to Jinja users, something to consider if you are coming from that kind of experience.

Pros of this kind of approach:

What follows in an example of how a template may look like, assuming that we want to render the index of a blog, with a list of posts and a preview of their content; do not worry, all the building blocks will be explained later.

<h1>{{blog.title}}</h1>
<p>Latest posts</p>
{% for post in blog.posts %}
<h2>{{post.title}}</h2>
<p>{{post.sections.0.body|abbrev</p>
<a href="{{post.url}}">Full article</a>
{% endfor %}

In this example are visible to main (and only) building blocks of the template engine offered by selmer:

Placeholders

Placeholders are identified by double curly braces, for example {{blog.tile}}, and essentially take the content of a variable and render it to the output, taking from the blog example:

<h1>{{blog.title}}</h1>

Assuming that title's value is "My awesome heading", the generated output will be:

<h1>My awesome heading</h1>

Placeholders can also access nested data structures like maps and sequences using the dot notation; building on top of the previous example assume that we have a map representing a blog post with title and sections and we want to render a preview, showing just title and the first section, example map

{:title "A blog post"
 :sections [{:title "Section 1"
             :body "Some very long text"}
            {:title "Section 2"
             :body "Some other long text"}]}

And the preview template, assuming that we want to show the preview of the first section of a post.

<h1>{{post.title}}</h1>
<h2>{{post.sections.0.title}}</h2>
<p>{{post.sections.0.body}}</p>

When rendered, the output will look like this

<h1>A blog post</h1>
<h2>Section 1</h2>
<p>Some very long text</p>

Filters

Filters can be piped to placeholders to alter their values before being sent to the output, the syntax is {{placeholder|filter1|filter2:extra<sub>param</sub>|…filterN}}.

These are essentially functions that takes as the first argument the result of the previous step, plus other optional parameters, and return a value to either be rendered or piped to the next filter. There are a lot of builtin filters and it is possible to add custom ones.

Here is a list a the builtin filters.

Tags

Tags provide a way to introduce logic inside templates, offering conditionals, iterations and composition via inheritance and fragment template loading, which enables template code reuse.

Commonly used tags are:

There are many more and like filters, tags can be extended to add more functionalities to your templates.

Please refer to the official docs for more details.

As a side note, selmer can be used out side the HTML rendering context, as a generic template engine even if I focuse on this aspect in this post.

Other options

Of course there are other options available but I am not going to cover them in this post. Worth mentioning:

Let me know if I have missed something or if you want a deep dive of another library, I am constantly looking for new topics to cover in this humble website.

Discuss