Skip to content

Instantly share code, notes, and snippets.

@Ciantic
Last active August 21, 2025 14:47
Show Gist options
  • Save Ciantic/4dabaa23abfebadad37645a468753a18 to your computer and use it in GitHub Desktop.
Save Ciantic/4dabaa23abfebadad37645a468753a18 to your computer and use it in GitHub Desktop.
SolidJS TODO example with logical createStore and methods
import { render } from "solid-js/web";
import { For, createSignal } from "solid-js";
import { createStore, produce } from "solid-js/store";
/**
* Reusable todo store, with logical state change functions
*/
function createTodos(initialTitle: string) {
const createTodo = (id: number, task: string) => ({
id,
task,
done: false,
check(value: boolean) {
setStore("todos", (f) => f.id == this.id, "done", value);
},
remove() {
setStore("todos", (f) => f.filter((i) => i.id !== this.id));
},
});
const [store, setStore] = createStore({
title: initialTitle,
todos: [createTodo(1, "Okay start adding todos")],
});
return {
todos: () => store.todos,
title: () => store.title,
addTodo: (task: string) => {
if (!task) {
return;
}
setStore(
produce((mutable) => {
mutable.todos.push(createTodo(Math.random(), task));
}),
);
// Alternatively with setStore
// setStore("todos", (f) => [...f, createTodo(Math.random(), task)]);
// setStore("todos", store.todos.length, createTodo(Math.random(), task)]);
},
// This is not needed, as each task has logical `check()` function
// checkTodo: (i: number, value: boolean) => {
// setStore("todos", i, "done", value);
// },
};
}
function Todos() {
const [value, setValue] = createSignal("Buy milk");
const todoManager = createTodos("Groceries");
return (
<div>
{todoManager.title()}
<ul>
<For each={todoManager.todos()}>
{(task, i) => (
<li>
<label style={{ "user-select": "none", cursor: "pointer" }}>
<input
type="checkbox"
checked={task.done}
onInput={(e) => task.check(e.target.checked)}
/>{" "}
<span
style={{
"text-decoration": task.done ? "line-through" : "none",
}}
>
{task.task}
</span>
</label>
<button type="button" onClick={() => task.remove()}>
Remove
</button>
</li>
)}
</For>
</ul>
<input
type="text"
value={value()}
onInput={(e) => {
setValue(e.target.value ?? "");
}}
/>
<button type="button" onClick={() => todoManager.addTodo(value())}>
Add TODO
</button>
</div>
);
}
render(() => <Todos />, document.getElementById("app")!);
// It is also possible to nest stores inside stores, e.g. there could be:
/*
function createTask(id: number, task: string) {
const [state, setTask] = createStore({
id,
task,
done: false,
check(value: boolean) {
setTask("done", value);
},
});
return state;
}
*/
// It could be put inside another store in array...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment