Skip to content

killianarts/almighty-html

Repository files navigation

ALMIGHTY-HTML – HTML S-expressions

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.

Example Project


How It Works

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)))

Quick Example

(</>
  (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>

Basic Usage

Step 1: Create a Component

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)))

Step 2: Combine Components

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.")))))

Step 3: Render to HTML

Use 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>

Fragments

<> — Fragment

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.

raw! — Raw Fragment

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!')")))

Expressions and Logic

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.

Conditional Rendering

(</>
  (div
    (if (> (random 10) 5)
        (</> (p "High!"))
        (</> (p "Low!")))))

Loop Rendering

(</>
  (ul
    (loop :for item :in items :collect
      (</> (li item)))))

Dynamic Props

ALMIGHTY-HTML supports both inline plist props and dynamic plist props.
(let ((props '(:class "btn" :href "/")))
  (</> (a props "Dynamic Link")))

Utilities

register-web-components

Makes Web Components usable in ALMIGHTY-HTML.
(register-web-components
 custom1 custom2)

(</>
  (custom1 :prop "val"
    (custom2)))

<custom1 prop="val">
  <custom2></custom2>
</custom1>

clear-web-components

Clears all registered Web Components.

clsx

Builds class strings conditionally. Removes nil and joins the remaining strings with spaces.
(clsx "btn" nil "primary")
;; => "btn primary"

License

MIT License

© 2026 Micah Killian

© 2018 Bo Yao (original flute project)

© 2024 Akira Tempaku (HSX)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors