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>