In this tutorial, we learn how to create a to-do app using the popular javascript framework React.
The first step would be setting up our React application and for that, you need to choose a development environment. For this project, we’ll use Vite, but feel free to choose another environment that suits your preferences.
If you don’t know how to set up React application with Vite Click here
1. Creating UI using tailwindcss
In this project we are going to use tailwindcss to create our UI more fascinating, so you need to install the tailwindcss. If you don’t know how to install tailwindcss in your project so do visit the official website of tailwindcss :- https://tailwindcss.com/.
After setting up our react application we will create a file called “Navbar.jsx” in our “src” folder, and will import it in our “App.jsx”. “Navbar.jsx” will contain navbar component which is the header of our application.
Code : “Navbar.jsx”
import React from "react";
const Navbar = () => {
return (
<div className="py-4 border border-gray-200 px-9 flex justify-between items-center">
<p className="text-xl font-semibold">XTodo</p>
</div>
);
};
export default Navbar;
Now, we will create another file in “src” folder called “Todo.jsx” and will import it in “App.jsx”. The “Todo.jsx” will contain the main UI of our todo app.
Code : “App.jsx”
import Navbar from "./Navbar";
import Todo from "./Todo";
function App() {
return (
<div>
<Navbar />
<Todo />
</div>
);
}
export default App;
Next, we will move to the “Todo.jsx”. This file will contain all the necessary code of our application.
First, we will create a button component called “Add a todo” with id “button-1”. Than we will create a form component with id “form-1″. form component will have a ‘input” component where the users will type their task and two button component (save and cancel). Where the button “Save” will save the task and display on the screen and “cancel” button will cancel the task .
Code : “Todo.jsx”
import React from "react";
const Todo = () => {
return (
<div className="m-4 flex flex-col ">
<div className="flex">
<button
id="button-1"
className="flex items-center justify-center gap-1 px-5 py-2 mt-5 text-white bg-blue-500 rounded-full"
>
{" "}
Add a todo{" "}
</button>{" "}
</div>
<form id="form-1">
<div className="p-6 mt-5 space-y-4 border border-gray-100 rounded-md shadow-sm">
<input
required
type="text"
placeholder="Enter Board name"
className="p-3 border border-gray-300 rounded-md shadow-sm h-15 w-60 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
/>
<div>
<button className="font-medium px-4 py-1.5 text-white bg-blue-500 border border-blue-500 rounded-md">
Save
</button>
<button
type="button"
className="px-4 py-1.5 ml-3 font-medium border border-gray-300 rounded-md"
>
Cancel
</button>
</div>
</div>
</form>
</div>
);
};
export default Todo;
This is how our UI is going to appear :
2. Open/Close Form
In our next step, when the “Add a todo” button is clicked, we want to open our form component where the user will set its task.
To add this functionality we need to create a state called “isFormOpen” with the initial value of “false”.
Then we will create a function called “handleAddtodoClicked” and will pass it to the onClick event of our button component with id “button-1”.
In the “handleAddtodoClicked” function, we will change the value of “isFormOpen” to the opposite of its current value using “setisFormOpen”.
At the end of our code, we will use an “if else” statement to control the “className” attribute of our form component. If “isFormOpen” is false, we will assign the “hidden” class to the attribute, which will hide the component. If “isFormOpen” is true, we will assign other classes that will show the component on the screen.
Code :
const [isFormOpen, setisFormOpen] = useState(false);
const handleAddtodoClicked = () => {
setisFormOpen(!isFormOpen);
};
// button component ---->
// <button
onClick={handleAddtodoClicked}
// id="button-1"
// className="flex items-center justify-center gap-1 px-5 py-2 mt-5 text-white bg-blue-500 rounded-full"
// >
Add a todo
</button>
// -----> form component
// <form
// id="form-1"
className={
isFormOpen
? "p-6 mt-5 space-y-4 border border-gray-100 rounded-md shadow-sm"
: "hidden"
}
>
// <input
// required
// type="text"
// placeholder="Enter Board name"
// className="p-3 border border-gray-300 rounded-md shadow-sm h-15 w-60 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
// />
// <div>
// <button className="font-medium px-4 py-1.5 text-white bg-blue-500 border border-blue-500 rounded-md">
// Save
// </button>
// <button
// type="button"
// className="px-4 py-1.5 ml-3 font-medium border border-gray-300 rounded-md"
// >
// Cancel
// </button>
// </div>
//</form>
This is how our todo app is gonna look :
3. Adding Task
We will create a state called “query” with the initial value of empty string to store the value entered into the input field and whenever something is typed, we will update the “query” with the new value.
Code :
const [query, setQuery] = useState("");
//<input
onChange={(e) => setQuery(e.target.value)} // this will update the value
// required
// type="text"
// placeholder="Enter Board name"
// className="p-3 border border-gray-300 rounded-md shadow-sm h-15 w-60 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
/>
Now, we will create another state called “task” with the initial value of empty array, it will be an Array of string where all the previouse or current “query” will be stored.
When the “handleSaveClicked” function is called, it will receive an event as a parameter from the “onSubmit” event of the form component.
Inside the function, we will stop the default action of the “onSubmit” event using “event.preventDefault()”.
Next, we will go through each item in the “task” array and add the current value of “query” to it. Finally, we will update the “task” array using the “setTask” function.
Code :
const [query, setQuery] = useState("");
const [task, setTask] = useState([]);
const handleSaveClicked = (e) => {
e.preventDefault();
setTask([...task, query]);
};
// ------> your code
<form
onSubmit={handleSaveClicked}
// id="form-1"
// className={
// isFormOpen
// ? "p-6 mt-5 space-y-4 border border-gray-100 rounded-md shadow-sm"
// : "hidden"
// }
// >
// <input
// onChange={(e) => setQuery(e.target.value)}
// required
// type="text"
// placeholder="Enter Board name"
// className="p-3 border border-gray-300 rounded-md shadow-sm h-15 w-60 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
// />
// <div>
<button
onClick={handleSaveClicked}
// className="font-medium px-4 py-1.5 text-white bg-blue-500 border border-blue-500 rounded-md"
>
Save
</button>
// <button
// type="button"
// className="px-4 py-1.5 ml-3 font-medium border border-gray-300 rounded-md"
// >
// Cancel
// </button>
// </div>
</form>
4. Mapping task
We will use the “map” method to display each task one by one on the screen.
By mapping through the “task” collection, we can access each element and its corresponding index as parameters.
The “element” parameter represents the current element being processed, while the “index” parameter represents the position of that element in the collection. This will allow us to display each task in sequence on the screen. We have also displayed a “X” component in front of every task which will be the sign to delete the “task”.
Next, we will pass the “element” parameter to a div component to display each task on the screen. This means that the value of “element” will be rendered within the div component, allowing us to display the content of each task. We will use “index” parameter to delete the “task”.
Code :
{task.map((element, index) => (
<div className="flex space-x-3 items-center">
<div className="text-xl">{element}</div>
<div
id="delete"
className="cursor-pointer text-xl text-red-500"
>
X
</div>
</div>
))}
5. Delete Todo
To delete a specific “task”, we need to create a function named “handleDeleteTask”. This function will be assigned to the div element with the id “delete”. Then we will pass the “index” value obtained from the “map” method as a parameter to the “handleDeleteTask” function. This will enable the function to identify which task to delete from the list of tasks.
Code :
//{task.map((element, index) => (
// <div className="flex space-x-3 items-center">
// <div className="text-xl">{element}</div>
<div
onClick={() => handleDeleteTask(index)}
className="cursor-pointer text-xl text-red-500"
>
X
</div>
// </div>
// ))}
The “handleDeleteTask” function will take the “index” parameter as input, which will be used to determine the task to be deleted from a list of tasks.
Now, inside the function, we will create a new array called “filteredTask” using the “filter” method on the “task” array. The “filter” method will create a new array that includes only the elements that meet a certain condition.
In this case, the condition is that the index of each element in the “task” array must not be equal to the “index” parameter passed to the function.
The resulting “filteredTask” array will contain all the tasks except for the one with the index specified in the “index” parameter. Finally, the “setTask” function will be called with the “filteredTask” array as its argument. This will update the state of the “task” array, removing the task that was deleted, and causing the component to re-render with the updated list of tasks.
Code :
const handleDeleteTask = (index) => {
const filteredTask = task.filter((element, i) => i !== index);
setTask(filteredTask);
};
I hope this tutorial helped you build your own todo app.
ALSO SEE- MAKE TIC-TAC-TOE GAME USING REACT