Simple and powerful HTML generation library
Find a file
2024-06-08 13:02:53 +09:00
.github/workflows Rename CI to test 2024-06-01 20:16:53 +09:00
src Improve rendering 2024-06-07 10:07:37 +09:00
tests Amend element test 2024-06-08 13:02:53 +09:00
.gitignore Add qlfile 2024-02-03 14:55:44 +09:00
hsx-test.asd Integrate defhsx package into hsx package 2024-06-06 14:59:46 +09:00
hsx.asd Define hsx package 2024-05-27 16:54:46 +09:00
LICENSE Update license 2024-02-09 20:21:04 +09:00
qlfile Add fiveam-asdf 2024-06-01 07:02:47 +09:00
qlfile.lock Add fiveam-asdf 2024-06-01 07:02:47 +09:00
README.md Add description of hsx macro 2024-06-06 21:20:38 +09:00

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