Summary
{{ loopVar.prop }} text interpolation inside an x-for loop renders empty when the loop lives inside a hydrated (kebab-tag) component. The same loop works at the view level, and x-text="loopVar.prop" works in both. The loop iterates the correct number of times — only the {{ }} text nodes are blank. Attribute directives that use the loop variable (e.g. @click="pick(it.id)") also work; it's specifically {{ }} text interpolation that doesn't receive the per-item scope inside a component.
Environment
@stacksjs/stx0.2.70bun-plugin-stx0.2.70 (dev server viabun-plugin-stx/serve)- Bun 1.3.13, macOS (darwin)
Reproduction
ReproList.stx (a component, in your partialsDir):
<script client>
const items = state([])
onMount(() => {
setTimeout(() => items.set([{ name: 'CompX' }, { name: 'CompY' }]), 60)
})
</script>
<ul id="repro-list">
<li x-for="it in items" class="interp">{{ it.name || 'none' }}</li>
<li x-for="it in items" class="xt" x-text="it.name || 'none'"></li>
</ul>xfor-repro.stx (a view, in your patterns), doing the same loop inline plus the component:
@section('content')
<script client>
const viewItems = state([])
onMount(() => {
setTimeout(() => viewItems.set([{ name: 'ViewX' }, { name: 'ViewY' }]), 60)
})
</script>
<ul id="view-interp"><li x-for="it in viewItems">{{ it.name || 'none' }}</li></ul>
<repro-list />
@endsectionLoad the view.
Expected vs actual
| where | directive | result |
|---|---|---|
view-level x-for | {{ it.name }} | ✅ ViewX, ViewY |
component x-for | {{ it.name }} | ❌ empty, empty |
component x-for | x-text="it.name" | ✅ CompX, CompY |
Rendered component HTML — the loop ran (2 <li class="interp">) but the {{ }} nodes are blank:
<li class="interp"></li>
<li class="interp"></li>
<li class="xt">CompX</li>
<li class="xt">CompY</li>Workaround
Use x-text (or bind via an attribute) for loop-variable values inside components:
<span x-text="it.name"></span> instead of <span>{{ it.name }}</span>.
Possibly related (same build pipeline)
In the served/inlined runtime, regex backslashes appear stripped from string-literal regexes. Two observed:
- the
x-for/:fortrailing-()retry ships asnew RegExp("(s*)s*$")instead of\(\s*\)\s*$, so the retry that recoverssignal()list expressions never fires (bare signal refs are required in:for); - the
inScopefirst-identifier regex ships as[A-Za-z_$][w$]*instead of[\w$]*, so the[STX] :for ... inScope=false root=<char>diagnostic only captures the first character of the identifier.
These may be unrelated to the interpolation-scope bug, but both point at string contents being mangled by the build.