2024-05-28 00:31:18 +00:00
# HSX
2018-06-24 17:08:30 +00:00
2024-12-20 14:38:19 +00:00
HSX (Hypertext S-expression) is a simple and powerful HTML (Living Standard) generation library for Common Lisp.
2024-12-12 05:00:42 +00:00
This project is a fork of [ailisp/flute ](https://github.com/ailisp/flute/ ).
## Warning
2024-12-12 16:35:31 +00:00
This software is still in ALPHA quality. The APIs are likely to change.
2024-12-12 05:00:42 +00:00
2024-12-12 16:35:31 +00:00
Please check the [release notes ](https://github.com/skyizwhite/hsx/releases ) for updates.
2024-05-27 09:08:25 +00:00
2024-06-08 04:43:57 +00:00
## Getting Started
2024-05-28 00:31:18 +00:00
2024-06-08 04:43:57 +00:00
### Basic Usage
2024-05-27 09:08:25 +00:00
2024-12-12 16:35:31 +00:00
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.
2024-05-28 10:33:08 +00:00
2024-05-27 09:24:19 +00:00
```lisp
2024-05-27 09:08:25 +00:00
(hsx
2024-06-08 04:43:57 +00:00
(div :id "example" :class "container"
(h1 "Welcome to HSX")
(p "This is an example paragraph.")))
2024-05-28 00:31:18 +00:00
```
2024-05-27 09:08:25 +00:00
2024-06-08 04:43:57 +00:00
This generates:
2024-05-27 09:08:25 +00:00
2024-05-28 00:31:18 +00:00
```html
2024-06-08 04:43:57 +00:00
< div id = "example" class = "container" >
< h1 > Welcome to HSX< / h1 >
< p > This is an example paragraph.< / p >
2024-05-27 09:08:25 +00:00
< / div >
```
2024-12-12 16:35:31 +00:00
To convert an HSX object into an HTML string, use the `render-to-string` function:
```lisp
(render-to-string
(hsx ...))
```
### Embedding Content
2024-06-08 04:43:57 +00:00
2024-12-12 16:35:31 +00:00
HSX allows you to embed Common Lisp forms directly within your HTML structure.
2024-06-08 04:43:57 +00:00
2024-12-12 16:35:31 +00:00
When working with HSX elements inside embedded Lisp forms, you should use the `hsx` macro again.
2024-05-27 09:08:25 +00:00
2024-05-27 09:24:19 +00:00
```lisp
2024-05-27 09:08:25 +00:00
(hsx
(div
2024-06-08 04:43:57 +00:00
(p :id (format nil "id-~a" (random 100)))
2024-05-27 09:08:25 +00:00
(ul
2024-12-12 04:09:51 +00:00
(loop
:for i :from 1 :to 5 :collect
(hsx (li (format nil "Item ~a" i)))))
2024-06-08 04:43:57 +00:00
(if (> (random 10) 5)
2024-12-12 04:09:51 +00:00
(hsx (p "Condition met!"))
(hsx (p "Condition not met!")))))
2024-05-28 00:31:18 +00:00
```
2024-05-27 09:08:25 +00:00
2024-06-08 04:43:57 +00:00
This might generate:
2024-05-27 09:08:25 +00:00
2024-05-28 00:31:18 +00:00
```html
2024-05-27 09:08:25 +00:00
< div >
2024-06-08 04:43:57 +00:00
< p id = "id-42" > < / p >
2024-05-27 09:08:25 +00:00
< ul >
2024-06-08 04:43:57 +00:00
< li > Item 1< / li >
< li > Item 2< / li >
< li > Item 3< / li >
< li > Item 4< / li >
< li > Item 5< / li >
2024-05-27 09:08:25 +00:00
< / ul >
2024-06-08 04:43:57 +00:00
< p > Condition not met!< / p >
2024-05-27 09:08:25 +00:00
< / div >
```
2024-06-08 04:43:57 +00:00
### Using Fragments
To group multiple elements without adding an extra wrapper, use the fragment `<>` .
2024-05-30 00:47:56 +00:00
```lisp
(hsx
(< >
2024-06-08 04:43:57 +00:00
(h1 "Grouped Elements")
(p "First paragraph.")
(p "Second paragraph.")))
2024-05-30 00:47:56 +00:00
```
This generates:
```html
2024-06-08 04:43:57 +00:00
< h1 > Grouped Elements< / h1 >
< p > First paragraph.< / p >
< p > Second paragraph.< / p >
2024-05-30 00:47:56 +00:00
```
2024-12-12 16:35:31 +00:00
### Creating Components
2024-05-28 10:33:08 +00:00
2024-12-12 16:35:31 +00:00
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.
2024-05-28 10:33:08 +00:00
```lisp
2024-12-12 16:35:31 +00:00
(defcomp ~card (& key title children)
2024-05-27 09:08:25 +00:00
(hsx
2024-06-08 04:43:57 +00:00
(div :class "card"
2024-05-27 09:08:25 +00:00
(h1 title)
2024-05-27 09:40:50 +00:00
children)))
2024-05-28 00:31:18 +00:00
```
2024-05-27 09:08:25 +00:00
2024-12-12 16:35:31 +00:00
Alternatively, you can use a property list:
2024-05-27 09:24:19 +00:00
2024-05-28 00:31:18 +00:00
```lisp
2024-12-12 16:35:31 +00:00
(defcomp ~card (& rest props)
2024-05-27 09:24:19 +00:00
(hsx
2024-06-08 04:43:57 +00:00
(div :class "card"
2024-05-27 09:24:19 +00:00
(h1 (getf props :title))
2024-05-27 09:40:50 +00:00
(getf props :children))))
2024-05-28 00:31:18 +00:00
```
2024-06-08 04:43:57 +00:00
Usage example:
2024-05-27 09:24:19 +00:00
2024-05-28 00:31:18 +00:00
```lisp
2024-05-27 09:40:50 +00:00
(hsx
2024-12-12 16:35:31 +00:00
(~card :title "Card Title"
2024-06-08 04:43:57 +00:00
(p "This is a card component.")))
2024-05-28 00:31:18 +00:00
```
2024-05-27 09:08:25 +00:00
2024-06-08 04:43:57 +00:00
Generates:
2024-05-27 09:08:25 +00:00
2024-05-28 00:31:18 +00:00
```html
2024-06-08 04:43:57 +00:00
< div class = "card" >
< h1 > Card Title< / h1 >
< p > This is a card component.< / p >
2024-05-27 09:08:25 +00:00
< / div >
```
2024-05-28 00:31:18 +00:00
## License
2024-05-27 09:08:25 +00:00
2024-06-08 04:43:57 +00:00
This project is licensed under the MIT License.
2024-02-08 17:54:12 +00:00
2024-05-28 10:33:08 +00:00
© 2024 skyizwhite
2024-02-08 17:54:12 +00:00
2024-05-28 10:33:08 +00:00
© 2018 Bo Yao
2024-06-08 04:43:57 +00:00
Feel free to contribute to the project and report any issues or feature requests on the [GitHub repository ](https://github.com/skyizwhite/hsx ).