Building a Todo App with Theme Toggle Using React

Abhishek Gurjar - Sep 10 - - Dev Community

Introduction

In this tutorial, we'll build a Todo List Web Application using React. This project helps in understanding state management, event handling, and working with lists in React. It’s perfect for beginners looking to strengthen their skills in React development.

Project Overview

The Todo List application allows users to add, mark as completed, and remove tasks. It offers a clean interface for managing daily tasks. This project showcases how React can be used to manage the state of a simple yet dynamic application.

Features

  • Add New Task: Users can add tasks to the list.
  • Mark as Completed: Users can mark tasks as done.
  • Delete Task: Users can delete tasks from the list.
  • Local Storage: Persists tasks across page reloads using localStorage.

Technologies Used

  • React: For building the user interface and managing component state.
  • CSS: For styling the application.
  • JavaScript: For the core logic and functionality.

Project Structure

The project structure follows a typical React project layout:

├── public
├── src
│   ├── components
│   │   ├── TodoList.jsx
│   │   ├── TodoItem.jsx
│   ├── App.jsx
│   ├── App.css
│   ├── index.js
│   └── index.css
├── package.json
└── README.md
Enter fullscreen mode Exit fullscreen mode

Key Components

  • TodoList.jsx: Handles the display and management of the todo list.
  • TodoItem.jsx: Manages individual todo items, including marking them as completed or deleting them.

Code Explanation

TodoList Component

This component handles the state of the entire todo list, including adding new tasks and rendering the list.

import { useState, useEffect } from "react";
import TodoItem from "./TodoItem";

const TodoList = () => {
  const [task, setTask] = useState("");
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    const savedTasks = JSON.parse(localStorage.getItem("tasks")) || [];
    setTasks(savedTasks);
  }, []);

  useEffect(() => {
    localStorage.setItem("tasks", JSON.stringify(tasks));
  }, [tasks]);

  const addTask = () => {
    if (task.trim()) {
      setTasks([...tasks, { text: task, completed: false }]);
      setTask("");
    }
  };

  const toggleCompletion = (index) => {
    const newTasks = tasks.map((t, i) =>
      i === index ? { ...t, completed: !t.completed } : t
    );
    setTasks(newTasks);
  };

  const deleteTask = (index) => {
    const newTasks = tasks.filter((_, i) => i !== index);
    setTasks(newTasks);
  };

  return (
    <div className="todo-list">
      <h1>Todo List</h1>
      <input
        type="text"
        value={task}
        onChange={(e) => setTask(e.target.value)}
        placeholder="Add a new task"
      />
      <button onClick={addTask}>Add Task</button>
      <ul>
        {tasks.map((t, index) => (
          <TodoItem
            key={index}
            task={t}
            index={index}
            toggleCompletion={toggleCompletion}
            deleteTask={deleteTask}
          />
        ))}
      </ul>
    </div>
  );
};

export default TodoList;
Enter fullscreen mode Exit fullscreen mode

TodoItem Component

The TodoItem component manages the display of each task, along with options to mark it as completed or delete it.

const TodoItem = ({ task, index, toggleCompletion, deleteTask }) => {
  return (
    <li className={task.completed ? "completed" : ""}>
      <span onClick={() => toggleCompletion(index)}>{task.text}</span>
      <button onClick={() => deleteTask(index)}>Delete</button>
    </li>
  );
};

export default TodoItem;
Enter fullscreen mode Exit fullscreen mode

In this component, we receive props from the parent TodoList and handle actions like toggling task completion or deleting the task.

App Component

The App.jsx serves as the root of the application, rendering the TodoList component.


import  { useState } from "react";
import "./App.css";
import TodoList from './components/TodoList';
import sun from "./assets/images/icon-sun.svg";
import moon from "./assets/images/icon-moon.svg";

const App = () => {
  const [isLightTheme, setIsLightTheme] = useState(false);

  const toggleTheme = () => {
    setIsLightTheme(!isLightTheme);
  };

  return (
    <div className={isLightTheme ? "light-theme" : ""}>
      <div className="app">
        <div className="header">
          <div className="title">
            <h1>TODO</h1>
          </div>
          <div className="mode" onClick={toggleTheme}>
            <img src={isLightTheme ? moon : sun} alt="theme-icon" />
          </div>
        </div>
        <Todo />
        <div className="footer">
        <p>Made with ❤️ by Abhishek Gurjar</p>
      </div>
      </div>

    </div>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

CSS Styling

The CSS ensures the Todo List application is user-friendly and responsive.

* {
  box-sizing: border-box;
}
body {
  margin: 0;
  padding: 0;
  font-family: Josefin Sans, sans-serif;
}

.app {
  width: 100%;
  height: 100vh;
  background-color: #161722;
  color: white;
  background-image: url(./assets//images/bg-desktop-dark.jpg);
  background-repeat: no-repeat;
  background-size: contain;
  background-position-x: center;
  background-position-y: top;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-direction: column;
}
.header {
  width: 350px;
  margin-top: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.title h1 {
  font-size: 30px;
  letter-spacing: 7px;
}
.mode {
  display: flex;
  align-items: center;
  justify-content: center;
}
.mode img {
  width: 22px;
}

.todo {
  width: 350px;
  flex-direction: column;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
.input-box {
  border-bottom: 1px solid white;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #25273c;
  width: 100%;
  gap: 10px;
  padding: 8px;
  border-radius: 10px;
}
.check-circle {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid white;
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: linear-gradient(to right,hsl(230, 50%, 20%) , hsl(280, 46%, 28%));
}

.input-task {
  width: 90%;
  border: none;
  color: white;
  background-color: #25273c;
}
.input-task:focus {
  outline: none;
}
.todo-list {

  margin-top: 20px;
  width: 350px;
  background-color: #25273c;
}
.todo-box {

  margin-inline: 15px;
  margin-block: 10px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 15px;
}
.todo-box .cross{
width: 14px;
}
.details {
  margin-bottom: 40px;
border-bottom: 1px solid white;
  width: 350px;
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  background-color: #25273c;
  font-size: 12px;
  padding: 12px;
  border-bottom-right-radius: 7px;
  border-bottom-left-radius: 7px;
}

.details .clickBtn{
  cursor: pointer;

}
.details .clickBtn:hover{
color: #3074fd;

}


/* //light Theme  */


.light-theme .app {
  background-color: #fff;
  color: #000;
  background-image: url(./assets//images/bg-desktop-light.jpg);
}

.light-theme .header {
color: white;
}

.light-theme .input-box{
  background-color: white;
  color: black;
  border-bottom: 1px solid black;
}
.light-theme input{
  background-color: white;
  color: black;
}
.light-theme .check-circle{
  border:1px solid black;

}
.light-theme  .todo-list{
  background-color: white;
  color: black;
}
.light-theme .details{
  border-bottom: 1px solid black;
  background-color: white;
  color: black;
}

.footer{
 margin: 40px;
}
Enter fullscreen mode Exit fullscreen mode

The styles ensure the Todo List is simple and clean while allowing for task management.

Installation and Usage

To get started, clone the repository and install the dependencies:

git clone https://github.com/abhishekgurjar-in/todo-app.git
cd todo-list
npm install
npm start
Enter fullscreen mode Exit fullscreen mode

The application will start running at http://localhost:3000.

Live Demo

Check out the live demo of the Todo List here.

Conclusion

The Todo List project is a great way to practice working with state, lists, and event handling in React. It demonstrates how to build a useful application that can persist data across sessions using localStorage.

Credits

  • Inspiration: Inspired by the need for a simple and effective task management tool.

Author

Abhishek Gurjar is a passionate web developer. You can check out more of his projects on GitHub.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player