2 Kindly Annotations
Kindly is a convention from the Clojure ecosystem for annotating values with rendering intent. Janqua supports Kindly metadata, so the same code patterns work in both Jank+Quarto and Clojure+Clay.
Without an annotation, results display as code output:
(let [people [{:name "Alice" :scores [85 92 78]}
{:name "Bob" :scores [91 88 95]}
{:name "Carol" :scores [76 80 89]}]]
(map (fn [p]
{:name (:name p)
:avg (/ (apply + (:scores p)) (count (:scores p)))})
people))({:name "Alice", :avg 85} {:name "Bob", :avg 274/3} {:name "Carol", :avg 245/3})Add Kindly metadata to control how a value is rendered.
2.1 ^:kind/hiccup — HTML from data
Converts a hiccup vector to HTML. Hiccup represents HTML as nested Clojure vectors:
^:kind/hiccup
[:svg {:width "100" :height "100" :xmlns "http://www.w3.org/2000/svg"}
[:circle {:cx "50" :cy "50" :r "40" :fill "coral"}]]The vector [:tag {:attr "value"} content] becomes <tag attr="value">content</tag>.
2.2 ^:kind/html — raw HTML
Renders a string as raw HTML. Since strings can’t hold metadata in Clojure, wrap the expression in a vector:
^:kind/html
["<b>bold</b> and <em>italic</em>"]The vector is automatically unwrapped — Janqua extracts the first element for rendering.
2.3 ^:kind/md — markdown
Renders a string as markdown. Same wrapping rule as kind/html:
^:kind/md
["| a | b |\n| --- | --- |\n| 1 | 2 |"]| a | b |
|---|---|
| 1 | 2 |
2.5 ^:kind/mermaid — Mermaid diagrams
Renders a string as a Mermaid diagram. The Mermaid JS library is loaded automatically from CDN:
^:kind/mermaid
["graph LR\n A[Start] --> B{Decision}\n B -->|Yes| C[OK]\n B -->|No| D[Cancel]"]2.6 ^:kind/graphviz — Graphviz diagrams
Renders a string as a Graphviz DOT diagram. Requires Graphviz to be installed:
^:kind/graphviz
["digraph { rankdir=LR; A -> B -> C; A -> C; }"]2.7 ^:kind/tex — LaTeX formulas
Renders a string as a LaTeX formula via MathJax:
^:kind/tex
["\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}"]\[\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}\]
2.8 ^:kind/code — code display
Renders a string as syntax-highlighted Clojure code (for display, not evaluation):
^:kind/code
["(defn hello [name]\n (str \"Hello, \" name \"!\"))"](defn hello [name]
(str "Hello, " name "!"))2.9 ^:kind/vega-lite — Vega-Lite charts
Renders a map as a Vega-Lite chart. The JS library is loaded automatically from CDN:
^:kind/vega-lite
{:data {:values [{:x "A" :y 28} {:x "B" :y 55} {:x "C" :y 43}]}
:mark :bar
:encoding {:x {:field :x :type :nominal}
:y {:field :y :type :quantitative}}}2.10 ^:kind/plotly — Plotly charts
Renders a map as a Plotly.js chart. The spec should have :data and :layout keys:
^:kind/plotly
{:data [{:x [1 2 3 4] :y [10 15 13 17] :type "scatter" :mode "lines+markers"}]
:layout {:title "Simple Plotly Chart"}}2.11 Annotating in library functions
The ^:kind/... reader syntax attaches metadata at the call site. But metadata can also be attached programmatically with with-meta or vary-meta, which means library functions can annotate their return values. The caller doesn’t need to know about the rendering — the function handles it.
For example, a function that builds an SVG bar chart and tags it as hiccup:
(defn bar-chart [labels values]
(let [bar-width 40
gap 10
max-val (apply max values)
height 120
bars (map-indexed
(fn [i [label val]]
(let [x (+ 10 (* i (+ bar-width gap)))
bar-height (* (/ val max-val) height)]
[:g
[:rect {:x x :y (- height bar-height)
:width bar-width :height bar-height
:fill "steelblue"}]
[:text {:x (+ x (/ bar-width 2)) :y (+ height 15)
:text-anchor "middle" :font-size "12"}
label]]))
(map vector labels values))
total-width (+ 20 (* (count labels) (+ bar-width gap)))]
(with-meta
(into [:svg {:width total-width :height (+ height 25)
:xmlns "http://www.w3.org/2000/svg"}] bars)
{:kindly/kind :kind/hiccup})))#'user/bar-chartNow simply calling the function renders the chart — no annotation needed at the call site:
(bar-chart ["a" "b" "c"] [10 20 15])This is the key idea behind Kindly: rendering intent lives in the data, not in the document markup. Libraries can provide visualization functions that “just work” in any Kindly-aware tool — Janqua, Clay, or others.
2.12 Why wrap strings in vectors?
In Clojure (and Jank), metadata can only be attached to collections — vectors, maps, sets — not to primitive types like strings or numbers. So ^:kind/html "hello" won’t work.
The convention is to wrap the value in a vector:
^:kind/html ["<b>hello</b>"]Janqua automatically unwraps the vector for all string-valued kinds (kind/html, kind/md, kind/mermaid, kind/graphviz, kind/tex, kind/code), extracting the first element for rendering.
2.13 Code block attributes
These attributes go on the code fence and control display independently of Kindly. See the Quarto documentation on code cells for more options.
| Attribute | Effect |
|---|---|
echo=false |
Hide the source code, show only the result |
eval=false |
Show code without evaluating it |
2.14 Summary
| Kind | Value type | Renders as |
|---|---|---|
^:kind/hiccup |
vector (hiccup) | HTML |
^:kind/html |
[string] |
raw HTML |
^:kind/md |
[string] |
markdown |
^:kind/hidden |
any | nothing (evaluates silently) |
^:kind/mermaid |
[string] |
Mermaid diagram |
^:kind/graphviz |
[string] |
Graphviz diagram |
^:kind/tex |
[string] |
LaTeX formula |
^:kind/code |
[string] |
syntax-highlighted code |
^:kind/vega-lite |
map | Vega-Lite chart |
^:kind/plotly |
map | Plotly chart |
^:kind/echarts |
map | ECharts chart |
^:kind/cytoscape |
map | Cytoscape graph |
^:kind/highcharts |
map | Highcharts chart |
| (none) | any | code output |