A fully functional Todo List application built using React, Context API, and Tailwind CSS. The app supports adding, editing, completing, and deleting todos, with persistent storage using localStorage.
- Add new todos
- Edit existing todos
- Mark todos as completed/uncompleted
- Delete todos
- Auto-save todos to
localStorage - Fully styled with Tailwind CSS
- Global state management using Context API
- ⚛️ React (Hooks, Functional Components)
- 🎯 Context API for state management
- 💾 LocalStorage for data persistence
- 🎨 Tailwind CSS for styling
- 🔀 JavaScript (ES6+)
src/
│
├── components/
│ ├── TodoForm.jsx // Input field + Add button
│ └── TodoItem.jsx // Each todo item with edit, delete, complete
│
├── contexts/
│ └── TodoContext.js // React Context logic for global state
│
├── App.jsx // Main app with all logic and provider
└── index.css / main.jsx // Tailwind CSS & entry point
int
try point
We use createContext() to create TodoContext:
export const TodoContext = createContext(defaultValue)Then we wrap the app with the provider in App.jsx:
TodoProvider value={{todos, addTodo, updateTodo, deleteTodo, toggleComplete}}>gt; All components now have access to these via a custom hook:
export const useTodo = () =>gt; useContext(TodoContext);We keep the main todo list in state:
const [todos, setTodos] = useState([]);setTodos(prev =>gt; [{ id: Date.now(), ...todo }, ...prev]);setTodos(prev =>gt; prev.map(t =>gt; t.id === id ? updatedTodo : t));setTodos(prev =>gt; prev.filter(t =>gt; t.id !== id));setTodos(prev =>gt; prev.map(t =>gt; t.id === id ? { ...t, completed: !t.completed } : t));To persist todos across reloads:
useEffect(() =>gt; {
const todos = JSON.parse(localStorage.getItem("todos"));
if (todos?.length) setTodos(todos);
}, []);useEffect(() =>gt; {
localStorage.setItem("todos", JSON.stringify(todos));
}, [todos]);- Uses
useStateto manage input text - Calls
addTodo()from context on submit - Clears input after adding
addTodo({ todo, completed: false });Each todo can be:
- Toggled (via checkbox)
- Edited (via input + save button)
- Deleted (via ❌ button)
The component uses:
updateTodo(todo.id, { ...todo, todo: todoMsg });
toggleComplete(todo.id);
deleteTodo(todo.id);It manages local state for editing via:
const [isTodoEditable, setIsTodoEditable] = useState(false);Date.now()used for unique IDs.- Spread operator (
{ ...todo, todo: updatedMessage }) ensures immutability. - Controlled inputs maintain form data in state.
- Tailwind CSS provides fast styling without writing custom CSS.
git clone repo-url>gt;
cd project-directory>gt;
npm install
npm run devev Open http://localhost:5173 in your browser.
- Using Context API for clean state management across components
- Avoiding prop drilling with
useContext() - Leveraging custom hooks for cleaner access
- Persisting state with localStorage
- Practicing React patterns with functional components & hooksooks
- Add filters (All, Active, Completed)
- Use
uuidinstead ofDate.now()for better ID generation - Add animations with
Framer Motion - Add authentication and save todos per user using Firebase or Supabase