Shared state (namespace)

By default each ```interact block owns its own state independently — dragging one block's slider doesn't affect another. Use namespace <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