Checklist
The tasks live in a signal, and the column takes a function in children position — so it re-renders itself when the array changes. Rows are keyed by object identity: toggling one task writes a new array that reuses every other item, so only that row remounts.
// A container takes a FUNCTION in children position: the list re-renders itself whenever a
// signal it read changes. Rows are keyed by object reference, so toggling one task — a new
// array that reuses every other item — remounts that row alone.
type Task = { title: string, done: boolean }
const tasks = signal<Task[]>([
{ title: "Read the conventions", done: true },
{ title: "Fork an example", done: false },
{ title: "Run it on a phone", done: false },
{ title: "Ship something small", done: false },
])
const left = computed(() => tasks.value.filter(t => !t.done).length)
const toggle = (task: Task) =>
tasks.value = tasks.value.map(t => (t === task ? { ...t, done: !t.done } : t))
const Row = (task: Task) => UIButton([
UIColumn([]).style({ width: 22, height: 22, borderRadius: 11, border: 2,
borderColor: task.done ? "#22c55e" : "#39404f", bgColor: task.done ? "#22c55e" : "transparent" }),
UIText(task.title).style({ fontSize: 16, color: task.done ? "#5c6272" : "white",
textDecoration: task.done ? "line-through" : "none" }),
]).style({ height: 58, px: 16, gap: 14, borderRadius: 14, bgColor: "#151922", justifyContent: "flex-start" })
.onClick(() => toggle(task))
const screen = UIScreen([
UIText("Today").style({ fontSize: 30, fontWeight: 700, color: "white" }),
UIText(() => `${left.value} left`).style({ fontSize: 14, color: "#8b90a0", mb: 6 }),
UIScrollable(() => tasks.value.map(Row)).style({ flexGrow: 1, gap: 8 }),
]).style({ bgColor: "#0b0d12", px: 16, pt: "max(safe-top, 24px)", pb: "comfort-bottom" })
screen.open()
Press Run to launch the floating simulator. It stays open as you browse — opening another example just swaps the app inside it.