Tutorials — learn Spark by editing real components

Every step below is a real .html Spark component running natively — no sandbox, no compiler, the same runtime as production. Edit the source and the preview updates as you type. Zero to productive in an afternoon.

1.

▸ Try:

lesson-1.html — edit me

● live preview — the component above, mounted for real

Live demos — every demo runs the exact code shown

Core — spark-html

● live · bind:value, each loops with index, $: derived, add & remove

  • Ship it
  • Star the repo

2 items

components/demo-todos.html — exactly as it runs (style omitted)
<input bind:value="draft" placeholder="Add a todo…" />
<button class="add" :disabled="!draft.trim()" onclick="{add}">Add</button>

<ul>
  <template each="todo, i in todos">
    <li>
      <span>{todo}</span>
      <button class="x" onclick="{remove}" :data-i="i">✕</button>
    </li>
  </template>
</ul>
<p class="meta">{summary}</p>

<script>
  let todos = ['Ship it', 'Star the repo'];
  let draft = '';

  $: summary = todos.length + (todos.length === 1 ? ' item' : ' items');

  function add() {
    if (!draft.trim()) return;
    todos = [...todos, draft.trim()];
    draft = '';
  }

  function remove(event) {
    const i = Number(event.target.dataset.i);
    todos = todos.filter((_, idx) => idx !== i);
  }
</script>

The ecosystem — one tiny package per job

● live · spark-html-router — route.query is reactive, in both directions

route.path =

route.query = {}

watch the URL bar — writes go through history.replaceState, reads are reactive

components/demo-router.html — exactly as it runs (style omitted)
<p>route.path = <b>{route.path}</b></p>
<p>route.query = <b>{JSON.stringify(route.query || {})}</b></p>

<button onclick="{next}">?page={Number(route.query?.page || 1) + 1}</button>
<button onclick="{search}">?q=spark</button>
<button onclick="{clear}">clear query</button>

<script>
  const route = useStore('route');

  function next() { route.query.page = String(Number(route.query.page || 1) + 1); }
  function search() { route.query.q = 'spark'; }
  function clear() { navigate(location.pathname); }
</script>