Interact — text template
Inside an
```interactblock, declare a plain-text output template withtemplate stl:— embed control values into STL or any text and display them live. The "output side" of Interact controls — the most common and simplest template type.
When to use
- ✅ Lightweight calculators (substitute slider/input values into a text result)
- ✅ Configuration preview ("you selected = ..." live echo)
- ✅ STL node dynamic generation (drag a slider, change a node's confidence / description)
- ✅ Teaching formula echo (input → formula → result)
- ❌ Need a chart → use Vega-Lite template
- ❌ Need animation / SVG → use SVG template
- ❌ Complex layout / multiple sections → split into multiple interact blocks or use Layout
Basic syntax
\```interact
slider x 0 10 5 1
template stl:
[Selected value] -> [{x}]
\```
template <type>: declares the template type + colon. Everything after the colon is template content. {var} is a placeholder.
Renders: a slider with a live STL line below: [Selected value] -> [5]. Drag → number changes.
Template types
| Type | Use | Doc |
|---|---|---|
template stl: |
Output STL statements / arbitrary plain text | This page |
template vega-lite: |
Output a live chart (Vega-Lite spec) | Interact + Vega-Lite |
template svg: |
Output an SVG scene | SVG scenes |
The "stl" type name is historical — it doesn't only output STL, it can output any text. The
[A] -> [B]in the template is just text; it isn't actually parsed into STL nodes (unless you later feed the rendered output into STG).
Placeholder syntax {...}
Inside the template, { } wraps an expression that's evaluated live.
1. Direct variable reference
template stl:
[Weight] -> [{weight}]
[Name] -> [{name}]
[Active] -> [{enabled}]
2. Expressions
template stl:
[BMI] -> [{weight / (height * height)}]
[Discounted price] -> [{price * (1 - discount)}]
The mini DSL supports (see Computed for full details):
- Arithmetic:
+ - * / % ** - Comparison:
== != < > <= >= - Logical:
&& || ! - Ternary:
cond ? a : b - Functions:
pow(a, b)sqrt(x)abs(x)min(...)max(...)sin(x)cos(x)tan(x)log(x)exp(x)floor(x)ceil(x)round(x) - Constants:
pie
3. Format spec :fmt
template stl:
[BMI] -> [{bmi:.1f}] ← 1 decimal place
[Price] -> [${price:.2f}] ← 2 decimals (money)
[Percent] -> [{(rate*100):.1f}%] ← convert to percentage
[Sci] -> [{value:.3e}] ← scientific
[Int] -> [{count:.0f}] ← 0 decimals (force int)
[Width] -> [{x:>10.2f}] ← right-aligned 10-char wide + 2 decimals
Format spec syntax mirrors Python f-strings: {value:[align][width][.precision][type]}
| Type | Meaning | Example |
|---|---|---|
f |
float | {x:.2f} |
e |
scientific | {x:.3e} |
d |
int (force) | {x:d} |
s |
string | {name:s} |
% |
percent (auto ×100) | {rate:.1%} |
4. Escaping {{ }}
To output a literal { or } in the template, use double braces:
template stl:
JSON literal = {{"key": "value"}} ← outputs {"key": "value"}
Examples
Example 1: pure echo
\```interact
slider x 0 100 50 1
template stl:
[Current value] -> [{x}]
\```
Renders: slider + one line "Current value = 50"; live update on drag.
Example 2: multi-line STL output + formatting
\```interact
slider weight 40 120 70 1
slider height 1.4 2.1 1.7 0.01
template stl:
[Weight] -> [{weight} kg]
[Height] -> [{height:.2f} m]
[BMI] -> [{(weight / (height * height)):.1f}] ::mod(category="{(weight / (height * height)) < 18.5 ? "Underweight" : (weight / (height * height)) < 24 ? "Normal" : (weight / (height * height)) < 28 ? "Overweight" : "Obese"}")
\```
Renders: 3 lines of live STL output. Line 3's category uses nested ternaries to display BMI category. For repeated expressions, refactor to computed derived values.
Example 3: free text template (not STL)
\```interact
input name "Alice"
slider age 1 100 30 1
select role "Student" "Engineer" "Teacher" "Other"
template stl:
Hello, {name}!
You're a {age}-year-old **{role}**.
Next year you'll be {age + 1}.
\```
Renders: a free-text template (not constrained to STL form). The "stl" type name is really "plain text."
Example 4: configuration preview
\```interact
input projectName "my-app"
select stack "Next.js" "Astro" "SvelteKit"
toggle typescript true
toggle eslint true
template stl:
**Project config preview**:
\```bash
npx create-{stack:s} {projectName}{typescript ? " --typescript" : ""}{eslint ? " --eslint" : ""}
\```
\```
Renders: form → live-assembled command line. toggle with ternary appends flags conditionally.
Plain-text fallback behavior
```interact blocks render as code blocks in non-supporting readers. Template content preserves {var} literals — readers see the template source + control declarations, fully understanding the original document's intent.
\```interact
slider x 0 10 5 1
template stl:
[Selected value] -> [{x}]
\```
→ Plain-text reader sees the above (with {x} placeholder), knows "x is a dynamic value here."
| Reader | Render |
|---|---|
| Rho | Full interaction + template live-evaluation |
| GitHub web | Code block ({x} literal visible) |
| Obsidian | Same |
| VS Code default preview | Same |
| cat / less | Plain text |
Common pitfalls
1. Reference an undeclared variable
\```interact
slider x 0 10 5 1
template stl:
[Result] -> [{y}] ← ❌ y not declared
\```
→ Template outputs {y} literal or throws. All variables in template must first be declared via slider/input/select/toggle/computed.
2. Wrong format spec
template stl:
[BMI] -> [{bmi:.1}] ← ❌ Missing type char (should be .1f / .1e)
[BMI] -> [{bmi:.1f}] ← ✅
[BMI] -> [{bmi:f}] ← ⚠️ Default 6 decimals; may be too many
[BMI] -> [{bmi:.1f}] ← ✅ 1 decimal
Format specs require a type char (f / e / d / s / %).
3. Expressions with unescaped nested quotes
template stl:
[Label] -> [{name == "Alice" ? "Admin" : "User"}] ← ❌ template's " conflicts with outer
→ The " in the template clashes with the outer STL string semantics — undefined behavior.
Improvement: use single quotes in the mini DSL (if supported), or pre-compute in computed and reference the computed name.
4. Deep nesting with callout / layout
:::card
\```interact
slider x 0 10 5 1
template stl:
[Selected] -> [{x}]
\```
:::
✅ Legal. But the interact block's height changes with template output length. Keep template output line count stable or give the container a fixed min-height.
5. Template output contains markdown special chars
template stl:
[Selected] -> [{x}] ← `[` `]` are markdown link syntax
In practice, usually fine — Rho renders template output as a fenced code block result, not triggering markdown link parsing. But watch out for * _ and other emphasis chars in template output.
6. Trying to chart with stl template
template stl:
draw a bar chart: {...} ← ❌ stl template doesn't render charts
→ stl template outputs plain text only, no graphical rendering. For charts use template vega-lite: (see Interact + Vega-Lite).
7. Template output expects markdown rendering
template stl:
**bold** and *italic* ← ❌ These chars output as literals, not bold/italic
→ Template defaults to plain-text output, no further markdown rendering. Some reader implementations support template html: or template markdown:, but not universal — stick to plain text for safety.
See also
- Interact controls — Control declarations
- Computed — Derived values (avoid complex expressions in template)
- Interact + Vega-Lite chart — chart template
- SVG scenes — svg template
- Shared state (namespace)
- Plain-text fallback principle