Skip to main content
Multiple todo lists with inline editing, validation, and dynamic groups — all running client-side with no server calls.

How It Works

The state is an array of groups, each containing a name, a todos array, and a new_todo input buffer. ForEach iterates the groups, and a nested ForEach iterates each group’s todos. Nested loopswith ForEach("groups") as (gi, group) destructures the loop binding into an index (gi) and item (group), matching Python’s enumerate convention. Each ForEach automatically captures $item and $index into scoped let bindings, so the outer loop’s group and gi survive even after the inner loop shadows $item and $index. The inner ForEach(f"groups.{gi}.todos") as (ti, todo) uses gi to target the right group and ti to target individual todos. Inline editing — instead of showing todo text as a Text component, each item uses a borderless Input styled with border-0 shadow-none p-0 so it looks like plain text but is directly editable. Dot-path auto-binding handles the read and write — the input’s name points at the exact item in state (f"groups.{gi}.todos.{ti}.text"). Disabling the Add buttondisabled=~group.new_todo evaluates to true when the input is empty, so the button stays disabled until you type something. group is the outer ForEach’s item, so group.new_todo accesses the group’s input buffer. Hiding completed items — each group has a show_done flag toggled by a small checkbox in the footer. Inside the inner todo loop, If(~todo.done | group.show_done) checks the todo’s completion against the group’s visibility flag. Both references survive nesting because ForEach’s auto-bind captured them. Adding a group — the dashed card at the end appends a new group object with AppendState("groups", {...}). ForEach picks it up and renders a new card automatically.