Interactivity

Block Fields And Repeaters

Block fields can be passed into Svelte islands, or rendered with normal TemplateX loops while browser state controls the interaction.

Read Block Fields In Svelte#

Block fields are passed into generated Svelte islands as same-named values:

phpresources/views/blocks/profile-tabs.php
title: Profile Tabscategory: Layoutfields:  tabs: repeater    fields:      tab_title: text      tab_content: textarea---<script>  let activeTab = 0;</script><div class="tabs">  {#each tabs as tab, index}    <button      type="button"      class:active={activeTab === index}      onclick={() => activeTab = index}    >      {tab.tab_title}    </button>  {/each}  {#if tabs[activeTab]}    <div>{tabs[activeTab].tab_content}</div>  {/if}</div>

Repeaters become arrays. Text fields become strings. Toggles become booleans. Image, gallery, and other structured fields keep their field shape.

Do not redeclare a field name in <script> unless you mean to create a local value with the same name. If the script already declares a name, TemplateX leaves that declaration alone.

Keep A Repeater On The Server#

Sometimes the first render should stay a normal TemplateX loop, but each row needs to update browser state:

phpresources/views/blocks/profile-tabs.php
title: Profile Tabscategory: Layoutfields:  tabs: repeater    fields:      tab_title: text      tab_content: textarea---<script>  let activeTab = 0;</script>{{ tabs as tab, count }}  <button type="button" onclick="{{ activeTab = count }}">    {{ count }}    {{ tab_title }}  </button>{{ /tabs }}<p>Active tab: {{ activeTab }}</p>

{{ count }} and {{ tab_title }} come from the server row. activeTab is shared browser state, so clicking a row can update later interactive output.

Use this shape when the server row context matters. Use native {#each tabs as tab} when the whole collection should be controlled by Svelte.