Home

Awesome

HSX

HSX (Hypertext S-expression) is a simple and powerful HTML (Living Standard) generation library for Common Lisp.

This project is a fork of ailisp/flute.

Warning

This software is still in ALPHA quality. The APIs are likely to change.

Please check the release notes for updates.

Getting Started

Basic Usage

Use the hsx macro to create HTML elements. Attributes are specified using a property list after the element name, and child elements are nested directly inside.

(hsx
  (div :id "example" :class "container"
    (h1 "Welcome to HSX")
    (p "This is an example paragraph.")))

This generates:

<div id="example" class="container">
  <h1>Welcome to HSX</h1>
  <p>This is an example paragraph.</p>
</div>

To convert an HSX object into an HTML string, use the render-to-string function:

(render-to-string
  (hsx ...))

Embedding Content

HSX allows you to embed Common Lisp forms directly within your HTML structure.

When working with HSX elements inside embedded Lisp forms, you should use the hsx macro again.

(hsx
  (div
    (p :id (format nil "id-~a" (random 100)))
    (ul
      (loop
        :for i :from 1 :to 5 :collect
        (hsx (li (format nil "Item ~a" i)))))
    (if (> (random 10) 5)
        (hsx (p "Condition met!"))
        (hsx (p "Condition not met!")))))

This might generate:

<div>
  <p id="id-42"></p>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
  </ul>
  <p>Condition not met!</p>
</div>

Using Fragments

To group multiple elements without adding an extra wrapper, use the fragment <>.

(hsx
  (<>
    (h1 "Grouped Elements")
    (p "First paragraph.")
    (p "Second paragraph.")))

This generates:

<h1>Grouped Elements</h1>
<p>First paragraph.</p>
<p>Second paragraph.</p>

Creating Components

You can define reusable components using the defcomp macro. Component names must begin with a tilde (~). Properties should be declared using &key, &rest, or both. The body must return an HSX element.

(defcomp ~card (&key title children)
  (hsx
    (div :class "card"
      (h1 title)
      children)))

Alternatively, you can use a property list:

(defcomp ~card (&rest props)
  (hsx
    (div :class "card"
      (h1 (getf props :title))
      (getf props :children))))

Usage example:

(hsx
  (~card :title "Card Title"
    (p "This is a card component.")))

Generates:

<div class="card">
  <h1>Card Title</h1>
  <p>This is a card component.</p>
</div>

License

This project is licensed under the MIT License.

© 2024 skyizwhite

© 2018 Bo Yao

Feel free to contribute to the project and report any issues or feature requests on the GitHub repository.