Shared state (namespace)
By default each
```interactblock owns its own state independently — dragging one block's slider doesn't affect another. Usenamespace <name>to make multiple interact blocks share the same variables — declare sliders / computed once; reuse across many blocks.
When to use
- ✅ One set of sliders driving multiple outputs (e.g., 3 sliders for principal / rate / years; both a text block and a chart block use them)
- ✅ Multiple charts interspersed with prose (write a paragraph, place a chart, write more, place another — all using the same parameters)
- ✅ Layout / Tabs cards sharing data (left card has sliders, right card has the chart)
- ✅ Avoid duplicate declarations (5 interact blocks all need the same slider — writing it 5 times is a maintenance nightmare)
- ❌ Two genuinely independent calculators (two BMI calculators that shouldn't interfere — don't share namespace)
- ❌ As a "global variable bag" (a namespace should focus on a single context, not collect all variables)
Basic syntax
Add namespace <name> after ```interact:
\```interact namespace finance
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
\```
Some prose...
\```interact namespace finance
template stl:
[Rate] -> [{(rate*100):.1f}%]
[Years] -> [{years}]
\```
Renders: block 1 has 2 sliders; block 2 has no sliders (it just reuses the namespace's), only template output. Drag block 1's slider → block 2's output updates live.
namespace naming rules
- ASCII letters + digits + underscores
- Case-sensitive (
finance≠Finance) - Recommended semantic names (
finance/physics/bmi/chart_demo) - Doesn't share across pages — namespace is per-page only (close the page, state is gone)
Examples
Example 1: parameters + outputs + chart all sharing
**Compound interest calculator** — drag sliders to see changes.
\```interact namespace finance
slider principal 1000 100000 10000 1000
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
computed compound = principal * pow(1+rate, years)
computed gain = compound - principal
\```
Numerical results:
\```interact namespace finance
template stl:
[Principal] -> [${principal:.0f}]
[Final value] -> [${compound:.0f}]
[Net gain] -> [${gain:.0f}]
\```
Growth curve:
\```interact namespace finance
template vega-lite:
{
"data": {"sequence": {"start": 0, "stop": {years}, "step": 1, "as": "year"}},
"transform": [{"calculate": "{principal} * pow(1+{rate}, datum.year)", "as": "value"}],
"mark": "line",
"encoding": {"x": {"field": "year"}, "y": {"field": "value", "type": "quantitative"}}
}
\```
3 blocks share the finance namespace. Block 1 declares sliders + computeds; blocks 2 and 3 are template-only, reusing all variables. Dragging block 1's sliders drives blocks 2 and 3 live.
Example 2: Layout + namespace combo
\```layout grid cols=2
:::card accent=blue
**Inputs**
\```interact namespace bmi
slider weight 40 120 70 1
slider height 1.4 2.1 1.7 0.01
computed bmi_value = weight / (height * height)
template stl:
[Weight] -> [{weight} kg]
[Height] -> [{height:.2f} m]
\```
:::
:::card accent=green
**Result**
\```interact namespace bmi
template stl:
[BMI] -> [{bmi_value:.1f}]
[Category] -> [{bmi_value < 18.5 ? "Underweight" : bmi_value < 24 ? "Normal" : "Overweight"}]
\```
:::
\```
Layout provides visual organization; namespace provides state sharing — two orthogonal concerns working together.
Example 3: cross-section shared parameters
## Financial simulation
Let's look at simple retirement planning. First, set parameters:
\```interact namespace retire
slider currentAge 20 60 30 1
slider retireAge 50 75 65 1
slider monthly 100 5000 1000 100
slider annualRate 0 0.1 0.05 0.005
computed years = retireAge - currentAge
computed total = monthly * 12 * years * pow(1 + annualRate/12, 12*years)
\```
### Numerical results
\```interact namespace retire
template stl:
[Current age] -> [{currentAge}]
[Retire age] -> [{retireAge}]
[Investment period] -> [{years} years]
[Principal at retirement] -> [${total:.0f}]
\```
### Capital growth
\```interact namespace retire
template vega-lite: {...}
\```
### Key insight
You can see, raising `monthly` by $100 raises retirement principal by $... (live).
**Start early** + **invest consistently** > investing more in a short window.
The whole section's 4 interactive blocks share one namespace — readers drag one slider and the entire section's numbers + chart + commentary all update.
Example 4: multiple isolated namespaces
**Compare two investment plans** — A and B don't interfere.
Plan A:
\```interact namespace planA
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
template stl:
[A final] -> [${1000 * pow(1+rate, years):.0f}]
\```
Plan B:
\```interact namespace planB
slider rate 0 0.15 0.08 0.01
slider years 1 30 15 1
template stl:
[B final] -> [${1000 * pow(1+rate, years):.0f}]
\```
Readers can see both plans simultaneously under different parameters.
Two namespaces are isolated — A's rate and B's rate are completely independent.
Plain-text fallback behavior
namespace shows as a code-block literal in non-supporting readers — readers see \```interact namespace finance and understand the original intended cross-block sharing.
\```interact namespace finance
slider rate 0 0.15 0.05 0.01
\```
| Reader | Render |
|---|---|
| Rho | Full cross-block state sharing |
| GitHub web | Code block (namespace literal visible) |
| Obsidian | Same |
| VS Code default preview | Same |
| cat / less | Plain text |
The namespace name is self-documenting in source — readers seeing namespace finance understand the related blocks belong to the same context.
Common pitfalls
1. Forgot namespace → state isolated
\```interact
slider rate 0 0.15 0.05 0.01
\```
\```interact
template stl: [Rate] -> [{rate}] ← ❌ rate not declared in block 2
\```
→ Block 2 throws "undefined rate" or shows {rate} literal. Both blocks need the same namespace to share:
\```interact namespace foo
slider rate 0 0.15 0.05 0.01
\```
\```interact namespace foo
template stl: [Rate] -> [{rate}] ← ✅
\```
2. namespace case mismatch
\```interact namespace Finance
slider rate ...
\```
\```interact namespace finance ← ❌ Different case → not shared
template ...
\```
→ namespace is case-sensitive. Finance ≠ finance.
3. Same variable redeclared in same namespace
\```interact namespace foo
slider rate 0 0.15 0.05 0.01
\```
\```interact namespace foo
slider rate 0 0.20 0.10 0.05 ← ❌ Re-declares rate
\```
→ Second declaration is undefined behavior (may overwrite, may error, may keep the first). Each variable in a namespace is declared once — subsequent blocks just reference, not redeclare.
4. namespace abuse → "everything global"
\```interact namespace shared
slider a 0 10 5 1
slider b 0 10 5 1
slider c 0 10 5 1
... (40 sliders)
\```
→ One namespace overstuffed → readers can't tell which blocks relate. A namespace should focus on a single context (one calculator / one section's parameter panel). Multiple contexts → multiple namespaces.
5. Cross-page persistence expectation
<!-- on page A: -->
\```interact namespace foo
slider x 0 10 5 1
\```
<!-- on page B: -->
\```interact namespace foo
template stl: [{x}] ← ❌ x not declared in B; namespace doesn't cross pages
\```
→ namespace is per-page only — when you navigate to B, A's foo namespace is gone. Each page's namespace is independent.
6. Mixing namespace with external JS
\```interact namespace foo
slider rate 0 0.15 0.05 0.01
\```
<script>
// Want to read foo.rate from JS
</script>
→ namespace state isn't exposed to external JS — it's managed inside Rho's hydration. Rho isn't a JS framework — for JS integration, see Developer Reference hydration API.
7. Nesting doesn't break namespace isolation
\```layout
:::card
\```interact namespace foo
slider x 0 10 5 1
\```
:::
:::card
\```interact namespace bar
template stl: [{x}] ← ❌ Different namespaces; can't see foo's x
\```
:::
\```
→ Nesting doesn't affect namespace rules — namespace is the isolation boundary, independent of nesting. To share across cards, both interact blocks need the same namespace.
Best practices
1. Semantic namespace names
✅ finance / bmi_calc / physics_demo / retire_planning
❌ ns1 / tmp / data / state
2. Declare in the first block, reference later
\```interact namespace foo
slider a 0 10 5 1
slider b 0 10 5 1
computed sum = a + b
\```
\```interact namespace foo
template stl: [{sum}] ← Template only, no redeclare
\```
3. computed in the first block
Put computed in the same first block as the sliders — later blocks reference computed names directly, no duplicating expressions:
\```interact namespace bmi
slider weight 40 120 70 1
slider height 1.4 2.1 1.7 0.01
computed bmi_value = weight / (height * height)
computed category = bmi_value < 18.5 ? "thin" : ...
\```
\```interact namespace bmi
template stl: [{bmi_value:.1f}] [{category}]
\```
4. Scope your namespace
A namespace covers one section / one demo — don't let a namespace span the entire document. Multi-section docs → multiple namespaces.
See also
- Interact controls — Control declarations
- Interact text template — Template variable references
- Computed — Derived values inside namespace
- Nested DSL — Namespace and nesting are orthogonal
- Plain-text fallback principle