Skip to the demo
Demos

Reactive lists

The list renders with <For>, so any client change re-renders it without a round-trip. Add appends optimistically and then persists on the server; the row appears the instant you click and reconciles when the patch lands. Each × is a server action.

  • Open the network tab
  • Add an item and watch it appear instantly

2 items. The optimistic row survives interim patches and rolls back on its own if the server action fails.

@expose todos: Todo[] = [];
@expose draft = "";

@expose addTodo() {
  this.todos.push({ id: crypto.randomUUID(), text: this.draft });
  this.draft = "";
}
@expose removeTodo(id: string) {
  this.todos = this.todos.filter((t) => t.id !== id);
}

// optimistic add: shows now, reconciles when the action's patch lands
<button onClick={() => {
  $flow.appendOptimistic("todos", { id: `tmp-${Date.now()}`, text: this.draft });
  $flow.call("addTodo");
}}>Add</button>

// <For> — a reactive list (compiles to an Alpine x-for)
<For each={this.todos} keyBy="id">
  {(todo) => (
    <li>{todo.text}
      <button onClick={() => $flow.call("removeTodo", todo.id)}>×</button>
    </li>
  )}
</For>