HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
cgrand
enlive
Clojure2009–2024
cgrand / enlive

enlive

a selector-based (à la CSS) templating and transformation system for Clojure

27Distinct people
36Mentions
1Explicit recommenders
1.6KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

a selector-based (à la CSS) templating and transformation system for Clojure

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

My favorite library for this: https://github.com/cgrand/enlive

snikeris used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 5:04:57 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year36 dated mentions

Observed mentions: 2009-06-11 15:48:00 UTC to 2024-01-02 19:39:09 UTC.

02462009-01-01 00:00:00 UTC to 2010-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20092010-01-01 00:00:00 UTC to 2011-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2011-01-01 00:00:00 UTC to 2012-01-01 00:00:00 UTC (exclusive): 6 mentions; 1 submissions, 5 comments2012-01-01 00:00:00 UTC to 2013-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2013-01-01 00:00:00 UTC to 2014-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20162017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2024

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20092009-01-01 00:00:00 UTC2010-01-01 00:00:00 UTC101
20102010-01-01 00:00:00 UTC2011-01-01 00:00:00 UTC606
20112011-01-01 00:00:00 UTC2012-01-01 00:00:00 UTC615
20122012-01-01 00:00:00 UTC2013-01-01 00:00:00 UTC707
20132013-01-01 00:00:00 UTC2014-01-01 00:00:00 UTC202
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC606
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC404
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC101
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC000
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC000
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC000
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC000
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC000
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC202
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC000
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC101

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Enlive Enlive is a selector-based (à la CSS) templating library for Clojure. David Nolen wrote a nice tutorial. Another tutorial is by Brian Marick. There's a quickstart section in Clojure Cookbook. Where do I get support? On the Enlive Google Group Artifact All artifacts are published to clojars. Latest version is 1.1.6: [enlive "1.1.6"] What's new in Enlive? (most recent first) 1.1.6: ADD: exception message when html-resource not found. FIX: auto-reload on windows (also works with chestnut). Auto-reloading (1.1.2) (net.cgrand.reload/auto-reload *ns*) Each time a resource or file used by a template/snippet is updated the namespace is reloaded (as per (require ... :reload)). Misc Perf improvements Fixes to ${vars} substitutions Pluggable parsers! (1.1.1) The *parser* dynamic var controls the parser to be used by html-resource at runtime. (or you can pass {:parser XXX} as an additional arg). For templates and snippets whose sources are not read dynamically, you can opt for another parser either locally: (deftemplate ugh {:parser xml-parser} (java.io.StringReader. "<a><div>hello</div></a>") []) or globally for the declaring ns: (set-ns-parser! xml-parser) A parser is a function from InputStream to nodes. xml-parser, net.cgrand.tagsoup/parser and net.cgrand.jsoup/parser are the three builtin ones. ${vars} substitutions (1.1.1) The following selector + function is going to replace any ${var} in text and attributes by the value found in the map (or any function). [:#container any-node] (replace-vars {:name "world" :class "hello"}) hiccup-style helper (1.1.0) (content (html [:h3#hello "Hello worls"])) older stuff By default selector-transformation pairs are run sequentially. When you know that several transformations are independent, you can now specify (as an optimization) to process them in lockstep. Note that this doesn't work with fragments selectors. Example: [:a :selector] a-transformation [:another :selector] another-transformation [:a :dependent :selector] yet-another-transformation If the first two transformations are independent you can rewrite this code as: :lockstep {[:a :selector] a-transformation [:another :selector] another-transformation} [:a :dependent :selector] yet-another-transformation Transformations are now slightly restricted in their return values: a node or a collection of nodes (instead of freely nested collections of nodes). Dynamic selectors: selectors aren't compiled anymore. It means that you don't need to wrap them in (selector ...) forms anymore nor to eval them in the most dynamic cases. Fragment selectors allow to select adjacent nodes. They are denoted by a map of two node selectors (eg {[:h1] [:p]}), bounds are inclusive and they select the smallest matching fragments. Transformations (the right-hand parts of rules) are now plain old closures. These functions take one arg (the selected node) and return nil, another node or a collection of nodes. Rules are applied top-down: the first rule transforms the whole tree and the resulting tree is passed to the next rules. Nodes are transformed deep-first, that is: if a selector selects several nodes, descendants are transformed first. Hence, when the transformation is applied to an ancestor, you can "see" the transformed descendants (but you can not see your transformed siblings). /B /(T B) A if A and B are selected and transformed by T the the resulting tree is (T A ) \C \C Concepts snippet is a unit of your page. It may be logical or visual entry, such as header, footer, page element. Snippet is usually a part of a template, and may serve as a container for other snippets. For example, for navigation on the web page. For that, let’s first define an html template for the navigation. Snippets are created by using net.cgrand.enlive-html/defsnippet function and, same as templates, they require a corresponding HTML template file to be availble in a classpath. So, snippet function returns a seq of nodes, it can be used as a building block for more complex templates. templates combine snippets together, they serve like a basement for the snippets. In order to create a template, you can use net.cgrand.enlive-html/deftemplate function. deftemplate is used as something what you would call layout in some other templating systems. In essence, it’s either a self-contained page (rarely true in bigger applications), or a container for snippets. That said, a template is a returns a seq of string -- basically it's a snippet whose output is serialized. Templates return a seq of strings to avoid building the whole string. Templates and snippets transform a source (specified as a path (to access resources on the classpath), a File, a Reader, an InputStream, a URI, a URL, an element or a seq of nodes). Next concept is selectors, which are used within snippets and templates to identify the block of HTML code the transformation would be applied to. They’re very similar to CSS selectors, but also allow more sophisticated, predicate-based selections, for example, you can select a tag based on some part of content, or an attribute. Transformations are functions that triggered on the elements found by selectors. They receive content obtained selector, and modify it in some way. Quickstart tutorial Template If you want to go see the compiled version of the following steps all in one place, you can check out an example Ring application. First thing you need to start, is to define your first template: (require '[net.cgrand.enlive-html :as html]) (html/deftemplate main-template "templates/application.html" []) Now, you can start writing selectors and transformations for the given selectors. Let's add a title to the template. Given that your template already has <head> and <title> tags, let's insert a title. Content of templates/application.html: <!DO
Read the full README on GitHub

What Hacker News says

36 sources
Can you clarify what you mean by "simple templates"? It may not be along the lines of what you're hoping for (it may not be simple enough), but I've found Stasis[1] to be a powerful tool for static site generation. You can write plain old HTML pages and/or fragments, with your desired level or genericity, and then run them through a set of transformations[2] to fill in content, set attributes (e.g. classes, styles, whatever), un/wrap elements, and so on. [1] https://github.com/magnars/stasis [2] https://github.com/cgrand/enlive
In Static Website Generators Are the Next Big Thing
ClojureScript with Enfocus (https://github.com/ckirkendall/enfocus/) in the front-end, and Clojure with Enlive (https://github.com/cgrand/enlive) in the backend. It's not a SPA. I started it a while ago, before React/Om. If it were now I would write it as a SPA and use some React wrapper, probably Rum (https://github.com/tonsky/rum). As for HTML/CSS, no framework at all. I'm interested in simple, minimalistic, innovative design, and I don't think frameworks help to achieve that.
In Show HN: Omnimemory – Simple multi-device flashcards
Flow control does not belong in markup. My favourite templating system is enlive[1] (or enliven[2]). You use CSS-style selectors to select snippets of HTML to manipulate and then use code to duplicate, remove, move or replace these snippets, insert content, set attributes etc. The "template" is pure HTML without any additional markup and without any logic. The code then says "repeat this snippet for every item in this list and insert it over there" (or whatever you need). Markup does what its good at, code does what its good at. Works out really nicely. Although nowadays I use reagent and hiccup-style markup and write everything in code (but keep my components as pure and dumb as possible). [1] https://github.com/cgrand/enlive [2] https://github.com/cgrand/enliven
In Show HN: An Isomorphic JavaScript Framework Faster Than React
SSAX, SXML and SXSLT are available as a package for Racket: http://pkg-build.racket-lang.org/doc/sxml/ `raco pkg install sxml`[1] I was recently looking for an enlive[2]-like library to use with a Racket-based project and couldn't find one. Yes, Racket has powerful syntax manipulation and pattern matching[3] built-in, but I wanted functional transforms of X/HTML akin to what enlive gives me in my Clojure-based projects. SXSLT seems to fit the bill quite nicely. [1] http://docs.racket-lang.org/raco/ [2] https://github.com/cgrand/enlive [3] http://docs.racket-lang.org/guide/match.html
In XML and Scheme
This is why I love Enlive[1], Enfocus[2] and Kioo[3] (and Enliven[4] is looking awesome too!). Your logic stays in your code, the templates are snippets of pure HTML. Dynamic content is generated by manipulating and composing the snippets in code. Snippets can be defined in one large HTML file or many files - up to you. The code uses CSS selectors to choose which parts of the HTML to use and transform. For example, lets say I have a blog application: <body> <div>Welcome to my Blog</div> <div id="posts"> <div class="post"> <div class="title">My post</div> <div class="content">Post content here</div> <div class="comments"> <div class="comment">A comment</div> </div> </div> </div> </body> Then my code m
Read the rest
ight look something like this: (enlive/defsnippet comment-snippet "myfile.html" [:.comments] [comments] [:.comment] (enlive/clone-for [comment comments (enlivecontent comment)) (enlive/defsnippet post-snippet "myfile.html" [:#posts] [posts] [:.post] (enlive/clone-for [{:keys [title content comments} posts] [:.title] (enlive/content title) [:.content] (enlive/content content) [:.comments] (comment-snippet comments))) That is, parts of snippets are selected and transformed in some way (changing the content, adding/removing css classes or styles, setting attributes, prepending or appending content, wrapping or unwrapping tags, duplicating for each element in a list, etc). This lets you write your page elements as mocked up snippets with dummy data and then merge them together, fill in content, dynamically update attributes and classes all without putting any logic into the HTML. This also makes it very designer friendly because they can work in pure HTML and CSS without worrying about templating - they only need to make sure to follow your basic structure outline (ie making sure your selectors match the right thing). [1] https://github.com/cgrand/enlive [2] https://github.com/ckirkendall/enfocus [3] https://github.com/ckirkendall/kioo [4] https://github.com/cgrand/enliven
In Your templating engine sucks and everything you've ever written is spaghetti code

Showing the 15 most recent of 36 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.