Chapter 2: Build Core Todo
Deleting Todos
Deleting Todos
Time for the "D" in CRUD. Let's add a delete button with a confirmation step so users don't accidentally lose their todos.
The prompt
"Add a delete button to each todo item in the TodoList component. Show a small red trash icon or X button on the right side of each item. It should only appear on hover. When clicked, call an onDelete callback with the todo's ID. Add a confirm dialog before actually deleting."
What Claude Code adds
Claude Code will update the TodoList component to include a delete button:
interface TodoListProps {
todos: Todo[];
onToggle: (id: string) => void;
onDelete: (id: string) => void;
}
// Inside the map, after the title div:
<button
onClick={() => {
if (window.confirm('Delete this todo?')) {
onDelete(todo.id);
}
}}
className="opacity-0 group-hover:opacity-100 transition-opacity
text-gray-400 hover:text-red-500 p-1"
aria-label="Delete todo"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>The opacity-0 group-hover:opacity-100 trick makes the delete button invisible until the user hovers over the todo item. The group class on the parent div is what makes this work -- it's a Tailwind feature for styling children based on parent state.
Add the delete handler
"Add a deleteTodo function to page.tsx that filters out the todo with the given ID."
const deleteTodo = (id: string) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
// In the JSX:
<TodoList todos={todos} onToggle={toggleTodo} onDelete={deleteTodo} />The filter approach is even simpler than map -- just keep every todo that doesn't match the ID.
Test it
- Hover over a todo -- the X button should appear
- Click the X -- a confirmation dialog should pop up
- Click "OK" -- the todo disappears
- Click "Cancel" -- the todo stays
The window.confirm() dialog is basic but effective for a learning project. In a production app, you'd likely use a custom modal component. We can upgrade this later -- the important thing is that the delete logic works.
Accessibility note
Notice that Claude Code added aria-label="Delete todo" to the button. Since the button only has an icon (no text), screen readers need this label to tell users what the button does. Claude Code typically handles accessibility basics automatically, but it's good to be aware of them.
Three letters of CRUD are done: Create, Read, Delete. Next up: editing, which rounds out the full set.