### Configure Spinneret Behavior
Source: https://context7.com/ruricolist/spinneret/llms.txt
Examples of modifying global variables to control HTML output, including language, charset, line wrapping, pretty printing, spacing, and attribute validation.
```common-lisp
;; Set default language for html tag
(setf *html-lang* "fr") ; Default: "en"
(with-html-string (:html (:body "Bonjour")))
;; => "..."
;; Set charset
(setf *html-charset* "ISO-8859-1") ; Default: "UTF-8"
;; Control line wrapping column
(let ((*fill-column* 40)) ; Default: 80
(with-html-string
(:p "This is a very long paragraph that will wrap.")))
;; Disable pretty printing for production
(let ((*print-pretty* nil))
(with-html-string
(:div (:p "Compact output"))))
;; => "
Compact output
"
;; Suppress automatic spaces between elements
(let ((*suppress-inserted-spaces* t))
(with-html-string
(:span "no" "spaces" "here")))
;; Always quote attribute values
(let ((*always-quote* t))
(with-html-string
(:div :id "test" :class "box")))
;; => ""
;; Add custom attribute prefix for validation bypass
(pushnew "ng-" *unvalidated-attribute-prefixes* :test #'equal)
(with-html (:div :ng-app "myApp" :ng-controller "MainCtrl"))
;; Disable all attribute validation
(setf *unvalidated-attribute-prefixes* '(""))
```
--------------------------------
### Configuring attribute validation
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Examples for modifying attribute validation behavior by updating *unvalidated-attribute-prefixes*.
```common-lisp
(pushnew "ng-" *unvalidated-attribute-prefixes* :test #’equal)
```
```common-lisp
;; Disable attribute validation.
(setf *unvalidated-attribute-prefixes* '(""))
```
--------------------------------
### Conditional Table Generation with `get-html-path`
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Example of using `get-html-path` to conditionally render table elements only if not already within a table context.
```common-lisp
(defun tabulate (&rest rows)
(with-html
(flet ((tabulate ()
(loop for row in rows do
(:tr (loop for cell in row do
(:td cell))))))
(if (find :table (get-html-path))
(tabulate)
(:table (:tbody (tabulate)))))))
```
--------------------------------
### Controlling Spinneret Output Style (:tree)
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
When `*html-style*` is set to `:tree`, Spinneret prints every element as a block and text on a new line, resulting in more verbose but predictable output. This example uses `with-html-string`.
```common-lisp
(let ((*html-style* :tree))
(with-html-string
(:div
(:p "Text " (:a "link text") " more text"))))
=>
```
--------------------------------
### Controlling Spinneret Output Style (:human)
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
When `*html-style*` is set to `:human` (the default), Spinneret attempts to produce human-writable HTML. This example shows how nested elements and text are rendered.
```common-lisp
(let ((*html-style* :human))
(with-html
(:div
(:p "Text " (:a "link text") " more text"))))
=>
```
--------------------------------
### Getting Current HTML Path
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Use `get-html-path` to determine the current location within the HTML document structure, returning a list of open tags.
```common-lisp
(get-html-path) ;-> '(:table :section :body :html)
```
--------------------------------
### Basic HTML Generation with Spinneret
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Demonstrates the fundamental usage of Spinneret for generating a simple HTML page with a header, section, and footer. Includes defining a macro for page structure and a function to generate a shopping list.
```common-lisp
(in-package #:spinneret)
(defparameter *shopping-list*
'("Atmospheric ponds"
"Electric gumption socks"
"Mrs. Leland's embyronic television combustion"
"Savage gymnatic aggressors"
"Pharmaceutical pianos"
"Intravenous retribution champions"))
(defparameter *user-name* "John Q. Lisper")
(defparameter *last-login* "12th Never")
(defmacro with-page ((&key title) &body body)
`(with-html
(:doctype)
(:html
(:head
(:title ,title))
(:body ,@body))))
(defun shopping-list ()
(with-page (:title "Home page")
(:header
(:h1 "Home page"))
(:section
("~A, here is *your* shopping list: " *user-name*)
(:ol (dolist (item *shopping-list*)
(:li (1+ (random 10)) item))))
(:footer ("Last login: ~A" *last-login*))))
```
```html
Home page
Home page
John Q. Lisper, here is your shopping list:
10 Atmospheric ponds
6 Electric gumption socks
4 Mrs. Leland's embyronic television combustion
9 Savage gymnatic aggressors
6 Pharmaceutical pianos
9 Intravenous retribution champions
```
--------------------------------
### Comparing macro and deftag usage
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Illustrates the difference in argument syntax between standard macros and deftag-defined macros.
```common-lisp
(input "Default" :name "why" :label "Reason") ; defmacro
```
```common-lisp
(input :name "why" :label "Reason" "Default") ; deftag
```
--------------------------------
### Generate HTML as a string with with-html-string
Source: https://context7.com/ruricolist/spinneret/llms.txt
Captures generated HTML at runtime and returns it as a string.
```common-lisp
(defun generate-card (title content)
(with-html-string
(:div.card
(:h2.card-title title)
(:div.card-body content))))
(generate-card "Welcome" "Hello, World!")
```
```common-lisp
(let ((header-html (with-html-string
(:header (:h1 "Site Title")))))
(with-html
(:raw header-html)
(:main (:p "Content goes here"))))
```
--------------------------------
### Verbose Output with :tree and *print-pretty* nil
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Setting `*html-style*` to `:tree` and `*print-pretty*` to `nil` produces verbose but predictable output, ensuring all tags are closed and minimizing whitespace.
```common-lisp
(let ((*html-style* :tree)
(*print-pretty* nil))
(with-html-string
(:div
(:p "Text " (:a "link text") " more text"))))
=> "
"
```
--------------------------------
### HTML generation with macros
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Shows the use of standard macros to fix evaluation order issues in HTML generation.
```common-lisp
(defmacro field (control)
`(with-html (:p ,control)))
(defmacro input (name label &key (type "text"))
`(with-html
(:label :for ,name ,label)
(:input :name ,name :id ,name :type ,type)))
```
--------------------------------
### Query Tag Context with get-html-path
Source: https://context7.com/ruricolist/spinneret/llms.txt
Use get-html-path to inspect the current stack of open tags for conditional rendering logic.
```common-lisp
;; Tabulate function that conditionally wraps in table
(defun tabulate (&rest rows)
(with-html
(flet ((render-rows ()
(dolist (row rows)
(:tr (dolist (cell row)
(:td cell))))))
;; Only add table wrapper if not already in a table
(if (find :table (get-html-path))
(render-rows)
(:table (:tbody (render-rows)))))))
;; Standalone usage - adds table wrapper
(with-html-string
(tabulate '("A" "B") '("C" "D")))
;; => "
"
;; Querying the current path
(with-html
(:html
(:body
(:main
(format t "Path: ~a~%" (get-html-path))))))
;; Prints: Path: (:MAIN :BODY :HTML)
```
--------------------------------
### Incorrect HTML generation with functions
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Demonstrates why using standard functions for HTML generation fails due to incorrect evaluation order.
```common-lisp
;; Doesn't work
(defun field (control)
(with-html (:p control)))
(defun input (default &key name label (type "text"))
(with-html
(:label :for name label)
(:input :name name :id name :type type :value default)))
```
--------------------------------
### Dynamic Tag Selection with :TAG
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Employ the :TAG pseudo-tag to select an HTML tag at run time. The tag must be known to Spinneret.
```common-lisp
(:tag :name "div"
(:tag :name "p"
(:tag :name "span"
"Hello.")))
≡ (:div (:p (:span "Hello")))
```
--------------------------------
### Using selector-like syntax for classes and IDs
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Spinneret supports a shorthand syntax for specifying CSS classes and IDs directly in the tag name.
```common-lisp
(:div#wrapper (:div.section ...))
≡ (:div :id "wrapper" (:div :class "section" ...))
```
--------------------------------
### *html-style*
Source: https://context7.com/ruricolist/spinneret/llms.txt
Controls how Spinneret pretty-prints HTML output.
```APIDOC
## *html-style*
### Description
Controls how Spinneret pretty-prints HTML. :human (default) produces human-readable output; :tree prints every element as a block with all tags closed.
### Usage
(let ((*html-style* :human))
(with-html-string
(:div
(:p "Text " (:a :href "#" "link") " more text"))))
```
--------------------------------
### with-html-string
Source: https://context7.com/ruricolist/spinneret/llms.txt
A variant of with-html that captures the generated HTML at runtime and returns it as a string instead of writing to a stream.
```APIDOC
## with-html-string
### Description
Captures the HTML generated by the body and returns it as a single string.
### Parameters
- **body** (forms) - Required - The HTML structure to generate.
### Response
- **string** (string) - The generated HTML content.
```
--------------------------------
### Embedding Parenscript in Spinneret
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Shows how to use the :raw keyword with the ps macro to embed JavaScript within HTML output.
```common-lisp
(with-html-string
(:script
(:raw (ps
(defun greeting ()
(alert "Hello"))))))
=>
""
(with-html-string
(:div :onclick (:raw (ps (alert "Hello")))))
""
```
--------------------------------
### Generate Dynamic Tags and Attributes
Source: https://context7.com/ruricolist/spinneret/llms.txt
Use :tag for runtime tag selection and :attrs to pass attribute lists programmatically.
```common-lisp
;; Dynamic tag selection based on heading level
(defun heading (level text)
(with-html
(:tag :name (format nil "h~d" (clamp level 1 6))
text)))
(with-html-string
(heading 1 "Main Title")
(heading 2 "Subtitle")
(heading 7 "Too deep - becomes h6"))
;; Output:
;;
Main Title
;;
Subtitle
;;
Too deep - becomes h6
;; Dynamic attributes from a plist
(defun button (label &key (attrs nil))
(with-html
(:button :attrs attrs label)))
(with-html-string
(button "Click Me" :attrs (list :id "submit-btn"
:class "primary"
:disabled nil))) ; nil attrs are omitted
;; => ""
;; Combining dynamic tag and attributes
(defun make-element (tag-name attributes content)
(with-html
(:tag :name tag-name :attrs attributes
content)))
(with-html-string
(make-element "article"
(list :class "post" :data-id "123")
"Article content here"))
;; => "Article content here"
```
--------------------------------
### with-html
Source: https://context7.com/ruricolist/spinneret/llms.txt
The primary macro for generating HTML. It interprets its body as HTML syntax where keywords in function position become tags, keyword-value pairs become attributes, and other forms become content, writing directly to the *html* stream.
```APIDOC
## with-html
### Description
Generates HTML output by interpreting the provided body as HTML syntax. Keywords in function position are treated as tags, and keyword-value pairs are treated as attributes.
### Parameters
- **body** (forms) - Required - The HTML structure to generate, including tags, attributes, and Lisp expressions.
### Request Example
(with-html
(:div#wrapper
(:p "Hello World")))
```
--------------------------------
### Markdown Integration for Content
Source: https://context7.com/ruricolist/spinneret/llms.txt
Load `spinneret/cl-markdown` to render Markdown-formatted strings within Spinneret. This feature allows for easy inclusion of formatted text, links, and emphasis directly in your Lisp code.
```common-lisp
;; After loading spinneret/cl-markdown
;; Inline markdown formatting
(let ((url "https://example.com"))
(with-html-string
(:p ("Click [here](~a) for more info." url))))
;; => "
"
```
```common-lisp
;; Emphasis and formatting
(with-html-string
(:div
("This is *important* and this is **very important**.")))
;; => "
This is important and this is very important.
"
```
```common-lisp
;; Compare with equivalent Spinneret
(let ((link "https://example.com"))
(with-html-string
(:p "Click " (:a :href link "here") " for more info.")))
```
--------------------------------
### Define custom tags with deftag
Source: https://context7.com/ruricolist/spinneret/llms.txt
Creates reusable HTML abstractions that behave like native tags, supporting attribute parsing and pass-through.
```common-lisp
(deftag field (body attrs)
`(:div.form-field ,@attrs ,@body))
```
```common-lisp
(deftag labeled-input (body attrs &key name label (type "text"))
(once-only (name)
`(progn
(:label :for ,name ,label)
(:input :name ,name :id ,name :type ,type
,@attrs
:value (progn ,@body)))))
```
```common-lisp
(with-html
(field :class "required"
(labeled-input :name "email"
:label "Email Address:"
:type "email"
:required t
:placeholder "user@example.com"
"default@example.com")))
```
```common-lisp
(labeled-input :name "search" :label "Search:" :autofocus t "")
```
--------------------------------
### Interpreting HTML Trees at Runtime
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Use `interpret-html-tree` to interpret HTML trees at runtime using a subset of Spinneret syntax for maximum flexibility.
```common-lisp
(interpret-html-tree `(:div :id "dynamic!"))
=>
```
--------------------------------
### Markdown Integration for Inline Formatting
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
When `spinneret/cl-markdown` is loaded, strings in function position are compiled as Markdown, useful for inline formatting like links.
```common-lisp
(with-html
("Here is some copy, with [a link](~a)" link))
```
```common-lisp
(with-html
(:span "Here is some copy, with "
(:a :href link "a link.")))
```
--------------------------------
### Defining HTML abstractions with deftag
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Uses deftag to create reusable HTML components that handle attributes and body content effectively.
```common-lisp
(deftag field (control attrs)
`(:p ,@attrs ,@control))
(deftag input (default attrs &key name label (type "text"))
(once-only (name)
`(progn
(:label :for ,name ,label)
(:input :name ,name :id ,name :type ,type
,@attrs
:value (progn ,@default)))))
```
--------------------------------
### Generate HTML with with-html
Source: https://context7.com/ruricolist/spinneret/llms.txt
The primary macro for generating HTML output to the *html* stream, supporting CSS selectors and Lisp code integration.
```common-lisp
(with-html
(:doctype)
(:html
(:head
(:title "My Page"))
(:body
(:h1 "Welcome")
(:p "This is a paragraph."))))
```
```common-lisp
(with-html
(:div#wrapper
(:div.section.highlight
(:p.intro "Hello world"))))
```
```common-lisp
(let ((items '("Apple" "Banana" "Cherry")))
(with-html
(:ul
(dolist (item items)
(:li item)))))
```
--------------------------------
### Generating data attributes with :DATASET
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
The :DATASET argument allows for the programmatic generation of data-prefixed attributes from a plist.
```common-lisp
(:p :dataset (:duck (dolomphious) :fish 'fizzgigious
:spoon "runcible"))
≡ (:p :data-duck (dolomphious) :data-fish 'fizzgigious
:data-spoon "runcible")
```
--------------------------------
### Dynamic Attributes with :ATTRS
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Use the :ATTRS pseudo-attribute to evaluate a list of extra attributes and values at run time for dynamic HTML generation.
```common-lisp
(:p :attrs (list :id "dynamic!"))
=>
```
--------------------------------
### deftag
Source: https://context7.com/ruricolist/spinneret/llms.txt
A macro-writing macro used to define custom HTML abstractions that behave like native tags, supporting attribute parsing and pass-through.
```APIDOC
## deftag
### Description
Defines a custom HTML tag abstraction. Arguments are parsed as HTML attributes, and unhandled attributes are passed through to inner elements.
### Parameters
- **name** (symbol) - Required - The name of the custom tag.
- **body** (list) - Required - The body content of the tag.
- **attrs** (list) - Required - The attributes associated with the tag.
```
--------------------------------
### Specializing html-length for custom types
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Use this method to help the pretty-printer calculate the length of user-defined types like PURI URIs.
```common-lisp
(defmethod html-length ((uri puri:uri))
;; Doesn't cons.
(length (puri:render-uri uri nil)))
```
--------------------------------
### Insert Unescaped Content with :raw
Source: https://context7.com/ruricolist/spinneret/llms.txt
Use :raw to bypass HTML escaping for inline styles, scripts, or pre-generated HTML strings.
```common-lisp
;; Inline CSS (angle brackets need :raw to avoid escaping)
(with-html-string
(:style (:raw "
a > p { color: blue; }
.container { max-width: 1200px; }
")))
;; Without :raw, angle brackets get escaped
(with-html-string (:style "a > p { color: blue; }"))
;; => "" ; WRONG!
;; Inline JavaScript
(with-html-string
(:script (:raw "
function greet(name) {
alert('Hello, ' + name + '!');
}
")))
;; Inserting pre-generated HTML
(let ((external-html "★"))
(with-html-string
(:div.rating
(:raw external-html)
(:raw external-html)
(:raw external-html))))
```
--------------------------------
### Markdown Integration
Source: https://context7.com/ruricolist/spinneret/llms.txt
Use Markdown-formatted strings in function position.
```APIDOC
## Markdown Integration
### Description
Load spinneret/cl-markdown to use Markdown-formatted strings in function position. The string is compiled as Markdown, then processed with format using any provided arguments.
### Request Example
(let ((url "https://example.com"))
(with-html-string
(:p ("Click [here](~a) for more info." url))))
```
--------------------------------
### Shorthand for Data Attributes
Source: https://context7.com/ruricolist/spinneret/llms.txt
Use the `:dataset` keyword argument as a shorthand for specifying multiple `data-*` attributes. This simplifies adding custom data attributes to HTML elements.
```common-lisp
;; Using :dataset for data attributes
(with-html-string
(:div :dataset (:user-id 42
:role "admin"
:active t)
"User Info"))
;; => "
User Info
"
```
```common-lisp
;; Equivalent explicit form
(with-html-string
(:div :data-user-id 42
:data-role "admin"
:data-active t
"User Info"))
```
```common-lisp
;; Practical example with JavaScript data binding
(with-html-string
(:button :dataset (:action "delete"
:confirm "Are you sure?"
:target "item-123")
"Delete Item"))
```
--------------------------------
### Passing through unhandled attributes with deftag
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Demonstrates how deftag allows passing arbitrary attributes through to the underlying HTML element.
```common-lisp
(input :name "why" :label "Reason" :required t :class "special" "Default")
=>
```
--------------------------------
### Combining :TAG and :ATTRS for Dynamic HTML
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Combine :TAG and :ATTRS to dynamically select an HTML tag and its attributes simultaneously.
```common-lisp
(:tag :name "div" :attrs (list :id "dynamic!"))
=>
```
--------------------------------
### Manipulating HTML Path with `*html-path*`
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
Bind `*html-path*` to manipulate the nested tags, useful when the HTML document is split across multiple functions. Note: `*html-path*` has dynamic extent.
```common-lisp
(defun inner-section ()
"Binds *HTML-PATH* to replicate the depth the output is used in."
(with-html-string
(let ((*html-path* (append *html-path* '(:section :section))))
(:h* "Heading three levels deep"))))
(defun outer-section (html)
"Uses HTML from elsewhere and embed it into a section"
(with-html-string
(:section
(:h* "Heading two levels deep")
(:section
(:raw html)))))
(outer-section (inner-section))
;;
;;
Heading two levels deep
;;
Heading three levels deep
;;
;;
```
--------------------------------
### Control HTML Output Formatting
Source: https://context7.com/ruricolist/spinneret/llms.txt
Adjust the `*html-style*` variable to control how Spinneret pretty-prints HTML. Options include `:human` (default) for readability and `:tree` for block formatting with all tags closed.
```common-lisp
;; Default human-readable style
(let ((*html-style* :human))
(with-html-string
(:div
(:p "Text " (:a :href "#" "link") " more text"))))
;; => "
"
```
```common-lisp
;; Tree style with no pretty printing - compact but predictable
(let ((*html-style* :tree)
(*print-pretty* nil))
(with-html-string
(:div (:p "Hello " (:em "world")))))
;; => "
Hello world
"
```
--------------------------------
### :dataset
Source: https://context7.com/ruricolist/spinneret/llms.txt
Shorthand for specifying multiple data-* attributes using a single :dataset argument.
```APIDOC
## :dataset
### Description
Shorthand for specifying multiple data-* attributes using a single :dataset argument.
### Request Example
(with-html-string
(:div :dataset (:user-id 42
:role "admin"
:active t)
"User Info"))
```
--------------------------------
### Parenscript Integration
Source: https://context7.com/ruricolist/spinneret/llms.txt
Embed Parenscript-generated JavaScript in Spinneret HTML.
```APIDOC
## Parenscript Integration
### Description
Load spinneret/ps to embed Parenscript-generated JavaScript in Spinneret HTML. Use :raw! to insert the generated code.
### Request Example
(with-html-string
(:script
(:raw (ps:ps
(defun greet (name)
(alert (+ "Hello, " name "!")))))))
```
--------------------------------
### interpret-html-tree
Source: https://context7.com/ruricolist/spinneret/llms.txt
Interprets a tree structure as HTML at runtime using Spinneret syntax, useful for processing dynamically generated HTML structures.
```APIDOC
## interpret-html-tree
### Description
Interprets a tree structure as HTML at runtime using Spinneret syntax. Useful for processing dynamically generated HTML structures.
### Request Example
(with-html-string
(interpret-html-tree
'(:div :id "container"
(:h1 "Title")
(:p :class "intro" "Welcome!"))))
```
--------------------------------
### Parenscript Integration for JavaScript
Source: https://context7.com/ruricolist/spinneret/llms.txt
Integrate Parenscript with Spinneret by loading `spinneret/ps`. This allows embedding Parenscript-generated JavaScript within Spinneret HTML, useful for dynamic web content and event handlers.
```common-lisp
;; Embedding Parenscript in Spinneret (remember to use :raw!)
(with-html-string
(:script
(:raw (ps:ps
(defun greet (name)
(alert (+ "Hello, " name "!")))))))
;; => ""
```
```common-lisp
;; Inline event handlers with Parenscript
(with-html-string
(:button :onclick (:raw (ps:ps (alert "Clicked!")))
"Click Me"))
;; => ""
```
```common-lisp
;; Full page with Parenscript
(with-html-string
(:doctype)
(:html
(:head
(:script
(:raw (ps:ps
(defun toggle-menu ()
(let ((menu (ps:chain document (get-element-by-id "menu"))))
(setf (ps:@ menu style display)
(if (equal (ps:@ menu style display) "none")
"block"
"none"))))))))
(:body
(:button :onclick (:raw (ps:ps (toggle-menu))) "Toggle Menu")
(:nav#menu "Menu content"))))
```
--------------------------------
### Interpret HTML Tree at Runtime
Source: https://context7.com/ruricolist/spinneret/llms.txt
Use `interpret-html-tree` to process Lisp structures into HTML dynamically. It's useful for generating HTML from data or complex logic.
```common-lisp
;; Interpret a simple tree
(with-html-string
(interpret-html-tree
'(:div :id "container"
(:h1 "Title")
(:p :class "intro" "Welcome!"))))
;; Output:
;;
;;
Title
;;
Welcome!
;;
```
```common-lisp
;; Dynamic tag with interpret-html-tree
(with-html-string
(interpret-html-tree
'(:tag :name "section"
(:tag :name "header"
"Section Header"))))
```
```common-lisp
;; Building HTML from data
(defun render-menu (items)
(interpret-html-tree
`(:nav
(:ul
,@(loop for (label url) in items
collect `(:li (:a :href ,url ,label)))))))
(with-html-string
(render-menu '(("Home" "/")
("About" "/about")
("Contact" "/contact"))))
```
--------------------------------
### Automatic Heading Levels with :h*
Source: https://context7.com/ruricolist/spinneret/llms.txt
The :h* pseudotag automatically adjusts heading levels based on the nesting depth within :section elements.
```common-lisp
(with-html-string
(:article
(:h* "Document Title") ; Renders as h1
(:p "Introduction paragraph")
(:section
(:h* "First Section") ; Renders as h2
(:p "Section content")
(:section
(:h* "Subsection") ; Renders as h3
(:p "Subsection content")))
(:section
(:h* "Second Section") ; Renders as h2
(:p "More content"))))
;; Output:
;;
;;
Document Title
;;
Introduction paragraph
;;
;;
First Section
;;
Section content
;;
;;
Subsection
;;
Subsection content
;;
;;
;;
;;
Second Section
;;
More content
;;
;;
```
--------------------------------
### Using :RAW to bypass HTML escaping
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
The :RAW pseudotag prevents automatic escaping of HTML literals, which is necessary for inline scripts and styles.
```common-lisp
(with-html-string (:style "a > p{color: white;}"))
=> ""
(with-html-string (:style (:raw "a > p{color: white;}")))
=> ""
```
--------------------------------
### Disabling HTML parsing with :DISABLE-HTML
Source: https://github.com/ruricolist/spinneret/blob/master/README.md
The :DISABLE-HTML pseudotag prevents the with-html macro from descending into specific forms, useful for escaping complex syntax.
```common-lisp
(with-complicated-macro (:disable-html (:keyword-option-1 ...))
...)
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.