ALMIGHTY-HTML is a declarative, component-oriented HTML DSL for Common
Lisp. It lets you describe HTML structures and reusable components
directly in Lisp, safely render them to HTML strings, and seamlessly
integrate with your web applications.
ALMIGHTY-HTML is a fork of the hsx library. It no longer uses
package-inferred-system, making it compatible with the vend dependency
managing library. It also adds full support for SVG tags.
ALMIGHTY-HTML translates Lisp S-expressions into HTML by expanding them
into calls to create-element.
Each tag or component inside an (</> ...) form becomes:
(create-element type props children)For example:
(</>
(article :class "container"
(h1 "Title")
(p "Paragraph")
(ac-share-button :service :x)))Expands into:
(create-element :article
(list :class "container")
(list (create-element :h1 nil (list "Title"))
(create-element :p nil (list "Paragraph"))
(create-element #'ac-share-button
(list :service :x)
nil)))(</>
(div :id "main" :class "container"
(h1 "Hello, =ALMIGHTY-HTML=!")
(p "This is a simple paragraph.")))↓
<div id="main" class="container">
<h1>Hello, =ALMIGHTY-HTML=!</h1>
<p>This is a simple paragraph.</p>
</div>Components are defined using
define-component. They are simple Lisp functions
that return ALMIGHTY-HTML elements.
Component names must start with ac- and props should be declared with
&key and/or &rest. The special children key automatically receives
any nested elements.
(define-component ac-button (&key href class children)
(</>
(a :href href :class (clsx "btn" class)
children)))ALMIGHTY-HTML allows composition of components just like JSX.
(define-component ac-card (&key title children)
(</>
(div :class "card"
(h2 title)
(div :class "content"
children))))
(defparameter *view*
(</>
(div :class "container"
(ac-card :title "Hello"
(ac-button :href "/start" :class "primary"
"Get Started"))
(ac-card :title "Docs"
(p "Read the documentation to learn more.")))))render-to-string to produce a full HTML string. Pass :pretty t
for indented, human-readable output.
(render-to-string *view* :pretty t)Output:
<div class="container">
<div class="card">
<h2>Hello</h2>
<div class="content">
<a href="/start" class="btn primary">Get Started</a>
</div>
</div>
<div class="card">
<h2>Docs</h2>
<div class="content">
<p>Read the documentation to learn more.</p>
</div>
</div>
</div>Combine multiple elements without creating an extra parent tag.
(</>
(<>
(li "One")
(li "Two")))↓
<li>One</li>
<li>Two</li>Fragments are useful when returning multiple sibling elements from a component.
ALMIGHTY-HTML automatically escapes unsafe characters in text and
attribute values to prevent injection attacks. If you need to insert
raw, unescaped HTML, you can do so — but use it only with trusted
content, as it disables automatic escaping and may expose security
risks.
(</>
(script (raw! "alert('unsafe if user-generated!')")))You can embed any Lisp expression directly inside an
ALMIGHTY-HTML form.
Since ALMIGHTY-HTML is just Lisp syntax, you can use if, when, loop, or
any other macro to build dynamic content.
(</>
(div
(if (> (random 10) 5)
(</> (p "High!"))
(</> (p "Low!")))))(</>
(ul
(loop :for item :in items :collect
(</> (li item)))))ALMIGHTY-HTML supports both inline plist props and dynamic plist props.
(let ((props '(:class "btn" :href "/")))
(</> (a props "Dynamic Link")))Makes Web Components usable in
ALMIGHTY-HTML.
(register-web-components
custom1 custom2)
(</>
(custom1 :prop "val"
(custom2)))↓
<custom1 prop="val">
<custom2></custom2>
</custom1>nil and joins the
remaining strings with spaces.
(clsx "btn" nil "primary")
;; => "btn primary"MIT License
© 2026 Micah Killian
© 2018 Bo Yao (original flute project)
© 2024 Akira Tempaku (HSX)