sigildocs

(sigil web ui)

(sigil web ui) - Server-Driven Hypermedia Library

Enables dynamic, real-time web interfaces driven entirely from Sigil. The server is the source of truth; the client is a thin rendering layer.

Core concepts:

  • SSE events for real-time updates (sigil:morph, sigil:eval, sigil:redirect)
  • HTTP headers for single-target responses (Sigil-UI-Merge-*)
  • Declarative HTML attributes (data-sg-*) for client interactions

Example:

(import (sigil web ui)
        (sigil http))

;; Send an SSE event to update a target
(write-chunk (sse-morph target: "#chat" mode: "append"
                        content: `(div (@ (class "msg")) "Hello!")))

;; Return HTML with merge headers
(sigil-ui-response target: "#results" mode: "inner"
                   content: `(ul ,@(map render-item items)))

Exports

sse-morphprocedure

Format an SSE morph event.

Morphs HTML content into a target element. The content can be SXML (converted to HTML) or a string.

Parameters: target: CSS selector for the target element (e.g., "#chat") content: SXML or HTML string to morph mode: Morph mode (default: "morph") settle: Milliseconds to wait after morph (for CSS transitions)

Modes: "morph" - Intelligent diff/patch via idiomorph (default) "replace" - Replace target's outerHTML "inner" - Replace target's innerHTML "append" - Append to target's children "prepend" - Prepend to target's children "before" - Insert before target "after" - Insert after target "remove" - Remove target element (no content needed)

Example:

(sse-morph target: "#messages" mode: "append"
           content: `(div (@ (class "msg")) "Hello!"))
sse-removeprocedure

Format an SSE remove event.

Removes the target element from the DOM. Shorthand for (sse-morph target: TARGET mode: "remove").

Example:

(sse-remove target: "#notification")
sse-classprocedure

Format an SSE class event.

Adds or removes CSS classes on the target element.

Parameters: target: CSS selector for the target element add: Space-separated class names to add remove: Space-separated class names to remove

Example:

(sse-class target: "#panel" add: "visible active")
(sse-class target: "#btn" remove: "loading" add: "done")
sse-evalprocedure

Format an SSE eval event.

Executes a limited command on the client. Only use for things that can't be expressed as HTML state (focus, scroll).

Commands: "focus" - Focus the target element "scroll-to" - Scroll target into view (or to bottom with position: "bottom")

Example:

(sse-eval cmd: "focus" target: "#input")
(sse-eval cmd: "scroll-to" target: "#chat" position: "bottom")
sse-redirectprocedure

Format an SSE redirect event.

Redirects the browser to a new URL.

Example:

(sse-redirect url: "/login")
sse-reloadprocedure

Format an SSE reload event.

Tells the browser to re-fetch the current page and morph the result into the DOM using Idiomorph. Preserves scroll position, form state, and focus. Useful for live-coding: redefine a view function, then send a reload to see the update immediately.

Parameters: target: CSS selector for the element to reload (default: "body")

Example:

(sse-reload)                      ; reload full body
(sse-reload target: "#sidebar")   ; reload specific element

Format an SSE css-reload event.

Reloads CSS stylesheets in the browser without a full page reload. If href: is provided, only stylesheets matching that substring are reloaded. Otherwise all stylesheets are reloaded.

Example:

(sse-css-reload)                        ; reload all stylesheets
(sse-css-reload href: "styles.css")     ; reload specific stylesheet
sse-jsprocedure

Format an SSE js event.

Executes JavaScript code in all connected browsers.

Example:

(sse-js code: "console.log('hello')")

Build Sigil-UI headers for merge operations.

Returns a dict of headers to include in an HTTP response.

Example:

(http-response
  status: 200
  headers: (dict-merge (sigil-ui-headers target: "#results" mode: "append")
                       (dict content-type: "text/html"))
  body: "<div>New item</div>")

Create an HTML response with Sigil-UI merge headers.

Convenience helper that combines headers and body.

Example:

(sigil-ui-response target: "#chat" mode: "append"
                   content: `(div (@ (class "msg")) "Hello!"))

Create a redirect response using Sigil-UI header.

For JavaScript-enhanced clients, this triggers a client-side redirect. For non-JS clients, falls back to standard HTTP redirect.

Example:

(sigil-ui-redirect url: "/dashboard")

Create a batch SSE response for multi-target updates.

Returns SSE-formatted events in a single response. Useful when one action needs to update multiple targets.

Example:

(sse-response-batch
  (sse-morph target: "#sidebar" content: new-sidebar)
  (sse-morph target: "#main" content: new-main)
  (sse-eval cmd: "focus" target: "#input"))

Build an SXML attribute list, filtering out #f values.

Takes alternating name/value pairs and returns a list of (name value) entries suitable for splicing into SXML (@...) forms. Pairs where the value is #f are omitted.

Example:

`(div (@ (class "main")
        ,@(optional-attrs
            'id my-id
            'data-target target
            'disabled (and disabled "disabled"))))
sg-buttonprocedure

Create a button that triggers an action.

Example:

(sg-button "Like" action: "/api/like" method: "post"
           loading: "opacity-50")
sg-formprocedure

Create a form with action handling.

Example:

(sg-form (list
           (sg-email-field name: "email")
           (sg-password-field name: "password")
           (sg-submit-button "Login"))
         action: "/api/login" method: "post"
         target: "#result" error-target: "#errors")
sg-sseprocedure

Create an SSE-connected container.

Example:

(sg-sse '((div (@ (id "messages")))) url: "/events/chat" id: "chat")

Create an input field of any type.

Handles label wrapping, error display, and value coercion. Non-string values are auto-coerced: numbers become strings, #f omits the value attribute.

Example:

(sg-input-field type: "text" name: "title" label: "Title"
                value: some-value required: #t)
sg-text-fieldprocedure

Create a text input field.

Create an email input field.

Create a password input field.

Create a hidden input field.

Create a textarea field.

Value is auto-coerced: numbers become strings, #f becomes "".

Create a select dropdown field.

Options can be:

  • List of strings: ("a" "b" "c")
  • List of (value . label) pairs: (("a" . "Option A") ("b" . "Option B"))

Value is auto-coerced for comparison: numbers become strings.

Create a checkbox field.

Create a submit button.

flash-messageprocedure

Create a flash message notification.

Returns a div with role="alert" for accessibility. The type: controls the CSS class (sg-flash-success, sg-flash-error, etc.). When remove-after: is set, the element auto-removes after that many milliseconds.

Example:

(flash-message type: 'success message: "Saved!" remove-after: 3000)
(flash-message type: 'error message: "Failed to save")
sse-flashprocedure

Send a flash message via SSE.

Wraps sse-morph with mode "append" to add a flash message to a container element. Defaults to targeting "#sg-flash-container".

Example:

(sse-flash type: 'success message: "Record updated" remove-after: 3000)

Create a loading indicator element.

Returns a div with class "sg-loading". When active: is #t, adds the "active" class. Uses aria-hidden for accessibility.

Example:

(sg-loading-indicator id: "spinner")
(sg-loading-indicator id: "spinner" active: #t)
sg-modalprocedure

Create a modal dialog using the HTML <dialog> element.

Example:

(sg-modal (list (p "Are you sure?")
                (sg-modal-close "Cancel"))
          id: "confirm" title: "Confirm")

Create a button that opens a modal dialog.

Example:

(sg-modal-trigger "Open Settings" target: "#settings-modal")

Create a button that closes the nearest modal dialog.

Example:

(sg-modal-close "Cancel")

Create a table action descriptor for use with sg-data-table.

Example:

(sg-table-action "Edit" action: "/users/{id}/edit")
(sg-table-action "Delete" action: "/users/{id}"
                 method: "delete" confirm: "Delete this user?")
sg-data-tableprocedure

Create a data table with headers, rows, and optional actions.

Example:

(sg-data-table columns: '((name "Name") (email "Email"))
               rows: users
               row-actions: (list
                 (sg-table-action "Edit" action: "/users/{id}/edit")
                 (sg-table-action "Delete" action: "/users/{id}"
                                  method: "delete"
                                  confirm: "Delete?")))
sg-paginatorprocedure

Create a pagination navigator.

Renders prev/next links and page numbers. Links use sg-link internally for SSE morphing. Current page is displayed as a <span>. Ellipsis shown when page window doesn't cover full range.

Example:

(sg-paginator current-page: 3 total-pages: 10
              base-url: "/users" target: "#user-list"
              params: '((sort . "name")))

Return the Sigil Web UI JavaScript library as a string.

Use this to include the script in static builds or serve it from a custom route.

Example:

(http-response/text 200 (sigil-web-ui-script))

Create an HTTP handler that serves the Sigil Web UI script.

Example:

(router
  (route 'GET "/js/sigil-web-ui.js" (sigil-web-ui-handler))
  ...)

Generate SXML for including Sigil Web UI in a page head.

Parameters: idiomorph-url: URL for idiomorph library (default: CDN) script-url: URL for sigil-web-ui.js (default: /js/sigil-web-ui.js)

Example:

(html
  (head
    ,@(sigil-web-ui-head)
    (title "My App"))
  (body ...))