hsx/README.md

2.9 KiB

HSX

⚠️ This project is a work in progress. Roadmap

HSX (Hypertext S-expression) is a straightforward HTML5 generation library for Common Lisp.

This project is a fork of flute, originally created by Bo Yao.

Usage

With the hsx macro, you can construct HTML using S-expressions.

The role of the hsx macro is to detect symbols of built-in elements and import the corresponding functions on demand. It is not needed when invoking user components defined with the defcomp macro.

The property list (inline form is also available) following the element name is interpreted as attributes, while the remaining elements are interpreted as child elements.

When a property is given a boolean value:

  • t results in the key being displayed without a value.
  • nil results in the property not being displayed at all.
  • Any other type of value results in the key-value pair being displayed.
(hsx
  (div :id "greeting" :class "flex"
    (h1 "Hello World")
    (p
      "This is"
      (strong '(:class "red")
        "an example!"))))

This code generates the following HTML:

<div id="greeting" class="flex">
  <h1>Hello World</h1>
  <p>
    This is
    <strong class="red">an example!</strong>
  </p>
</div>

HSX elements are essentially functions, allowing you to compose them freely and embed Common Lisp code within them.

(hsx
  (div
    (p :id (+ 1 1))
    (ul
      (loop
        :for i :from 1 :to 3
        :collect (li (format nil "item~a" i))))
    (if t
        (p "true")
        (p "false"))))

This generates:

<div>
  <p id="2"></p>
  <ul>
    <li>item1</li>
    <li>item2</li>
    <li>item3</li>
  </ul>
  <p>true</p>
</div>

The fragment <> allows you to group multiple elements without introducing additional wrappers.

(hsx
  (<>
    (h1 "Title")
    (p "This is a paragraph.")
    (p "This is another paragraph.")))

This generates:

<h1>Title</h1>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>

You can create HSX components using the defcomp macro. Components are essentially functions that accept keyword arguments, a property list, or both.

The children property accepts the children of a component.

(defcomp card (&key title children)
  (hsx
    (div
      (h1 title)
      children)))

or

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

This can then be used as follows:

(hsx
  (card :title "card1"
    (p "Lorem ipsum...")))

Which generates:

<div>
  <h1>card1</h1>
  <p>Lorem ipsum...</p>
</div>

To output HSX as an HTML string, use the render-to-string method.

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

License

This project is licensed under the terms of the MIT license.

© 2024 skyizwhite

© 2018 Bo Yao