Complete reference for @clojurewasm/su and @clojurewasm/kiso public APIs.
(ns my.app
(:require [su.core :as su :refer [defc defstyle]]))Define a Custom Element with Shadow DOM.
(defc component-name
{:props {...} ...options} ;; optional
[props] ;; props argument (or [])
body)Options map:
| Key | Type | Description |
|---|---|---|
:props |
{name type} |
Prop declarations |
:style |
[stylesheet ...] |
Stylesheets to apply (from defstyle) |
:formAssociated |
boolean |
Enable form participation |
:delegatesFocus |
boolean |
Delegate focus to Shadow Root |
Prop types:
| Type | Description |
|---|---|
"string" |
HTML attribute, converted to string |
"number" |
HTML attribute, converted via Number() |
"boolean" |
HTML attribute, truthy check |
:atom |
Props Channeling: JS property, not serialized |
Behavior:
- Component name must contain a hyphen (Custom Element spec)
- Component function runs once (setup phase)
defcauto-wraps the final hiccup expression as a reactive render function- If body explicitly returns a
fn, auto-wrap is skipped (Form-2 pattern) - Auto-registered via
customElements.define()
(defc my-widget
{:props {:title "string" :count "number"}
:style [my-widget-styles]}
[{:keys [title count]}]
[:div.widget
[:h2 title]
[:span (str "Count: " count)]])Render a component tree into a DOM container. Returns an unmount function.
(su/mount container hiccup) -> unmount-fn| Parameter | Type | Description |
|---|---|---|
container |
Element |
DOM element to render into |
hiccup |
hiccup vector | Root component element |
(let [unmount (su/mount (js/document.getElementById "app")
[::my-app])]
;; Later: (unmount)
)Define a scoped CSS stylesheet.
(defstyle style-name
[selector {:property "value" ...}]
...)- Creates a
CSSStyleSheetvia Constructable Stylesheets API - Returns a stylesheet value — pass to
defcvia:style [...] - Cached by name (created once, shared across instances)
- Scoped to the component's Shadow DOM
Selector syntax:
| Form | CSS Output |
|---|---|
[:div {...}] |
div { ... } |
[:.class {...}] |
.class { ... } |
[:host {...}] |
:host { ... } |
[":host(.x)" {...}] |
:host(.x) { ... } |
["::slotted(p)" {...}] |
::slotted(p) { ... } |
Apply a stylesheet to the document (outside Shadow DOM).
(su/global-style! stylesheet)Appends the stylesheet to document.adoptedStyleSheets.
Run a side-effect that re-runs when tracked atoms change.
(su/effect fn) -> dispose-fn- Runs immediately on creation
- Tracks all atoms dereferenced during execution
- Re-tracks dependencies on each run (dynamic tracking)
- Returns a dispose function
(let [dispose (su/effect
(fn [] (js/console.log "Count:" @count)))]
(dispose))Create a lazy derived value.
(su/computed fn) -> computed-ref- Lazy: recomputes only when dirty and
.derefis called - Cached: returns last value if deps unchanged
- Trackable by effects and other computed values
(let [total (su/computed (fn [] (reduce + @items)))]
(.deref total))Register a callback that runs after the component mounts to the DOM.
(su/on-mount fn)Must be called during component setup (not inside render fn).
Register a callback that runs before the component is removed.
(su/on-unmount fn)Must be called during component setup.
Provide a value to all descendant components.
(su/provide key value)Must be called during component setup. Attaches a "su-context-request" event listener.
Retrieve a value provided by an ancestor.
(su/use-context key) -> valueDispatches CustomEvent("su-context-request") with bubbles: true, composed: true
(crosses Shadow DOM boundaries). Must be called during component setup.
Log atom state changes to the console.
(su/enable-trace)
(su/enable-trace {:filter (fn [a] (= (.-label a) "tasks"))})
(su/disable-trace)Output format: [atom:label] oldVal → newVal
Replace a component's render function at runtime (used by Vite plugin).
(su/hot-replace tag-name new-render-fn) -> booleanCalled automatically during HMR. You typically do not call this manually.
Tag format: :tag#id.class1.class2
| Part | Example | Result |
|---|---|---|
| Tag only | [:div] |
<div> |
| With ID | [:div#app] |
<div id="app"> |
| With class | [:div.card] |
<div class="card"> |
| Default div | [:.card] |
<div class="card"> |
Attributes:
| Key | Behavior |
|---|---|
:class |
Merged with tag classes |
:style |
Applied as object (camelCase keys) |
:on-* |
Event listener (e.g., :on-click) |
:ref |
DOM reference callback |
:slot |
Named slot assignment |
Children:
| Type | Rendering |
|---|---|
| String | Text node |
| Number | Text node (coerced) |
nil |
Skipped |
| Vector | Hiccup element (recursive) |
| Function | Reactive binding via bind() |
| Sequence | Flattened |
Component references:
| Context | Syntax |
|---|---|
| Same namespace | [::my-comp {:prop "val"}] |
| Cross namespace | [:ns/my-comp {:prop "val"}] |
Compile ClojureScript source to JavaScript.
import { compile } from '@clojurewasm/kiso/compiler';
const result = compile(source, options?);
// result.code — JavaScript string
// result.map — source map (if requested)Options:
| Key | Type | Description |
|---|---|---|
filename |
string |
Source filename for errors |
sourceMap |
boolean |
Generate source map |
codegenHooks |
Record<string, CodegenHook> |
Custom JS emitters |
Parse ClojureScript source into forms.
import { read, readAll } from '@clojurewasm/kiso/compiler';
const form = read('(+ 1 2)'); // single form
const forms = readAll(source); // all formsAnalyze a parsed form into an AST node.
import { analyze } from '@clojurewasm/kiso/compiler';
const node = analyze(form);Generate JavaScript from an AST node.
import { generate } from '@clojurewasm/kiso/compiler';
const js = generate(node);Unified error class with phase and location context.
import { CompileError } from '@clojurewasm/kiso';
// Properties: phase, filename, line, col, message
// Methods: format(), formatLocation()
try {
compile(source, { filename: 'app.cljs' });
} catch (err) {
if (err instanceof CompileError) {
console.error(err.format());
// [analyze] app.cljs:12:1: def requires a symbol
}
}import { cljs } from '@clojurewasm/kiso/vite';
export default {
plugins: [cljs()],
};The plugin:
- Compiles
.cljsfiles on demand - Generates source maps for debugging
- Supports HMR for su components
- Shows errors in Vite's error overlay with phase and location