DEV Community

Cover image for How to create a TODO with Tailwind CSS and JavaScript
Michael Andreuzza
Michael Andreuzza

Posted on

How to create a TODO with Tailwind CSS and JavaScript

It's Monday! Let's recreate the TODO app from the previous tutorial using Alpine JS but with JavaScript instead.

See it live and get the code

A refresh of what a todo app is

A TODO is a list of things that need to be done. It's a great way to keep track of tasks and prioritize them. It can be used for anything from personal projects to work tasks.

Structure

Understanding the code:

  • id="todo-component": This is the ID of the component that contains the input to add new todo and the list of todos.
  • id="addTodoButton": This is the ID of the button that adds a new todo when clicked.
  • id="newTodoInput": This is the ID of the input that holds the new todo.
  • id="todoList": This is the ID of the list that displays the todos.

Classes are removed for brevity, but I'll keep those classes relveant to the tutorial.

<div id="todo-component">
  <!-- Input to add new todo -->
  <div >
    <button
      id="addTodoButton"
      >Add</button
    >
    <input
      id="newTodoInput"
    />
  </div>
  <!-- List of todos -->
  <ul
    id="todoList">
  </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

The script

  • document.addEventListener("DOMContentLoaded", () => {: This is the event listener that will be used to add the event listeners to the DOM elements.
  • const todos = JSON.parse(localStorage.getItem("todos")) || [];: This is the variable that will hold the todos.
  • const todoList = document.getElementById("todoList");: This is the variable that will hold the list of todos.
  • const newTodoInput = document.getElementById("newTodoInput");: This is the variable that will hold the input to add new todo.
  • const addTodoButton = document.getElementById("addTodoButton");: This is the variable that will hold the button that adds a new todo.
  • const renderTodos = () => {: This is the function that will be used to render the todos.
  • todoList.innerHTML = todos: This is the code that will be used to render the todos.
  • document: This is the variable that will be used to access the DOM elements.
  • querySelectorAll('input[type="checkbox"]'): This is the code that will be used to access the checkboxes in the list of todos.
  • forEach((checkbox, i) => {: This is the code that will be used to iterate over the checkboxes in the list of todos.
  • checkbox.addEventListener("change", () => {: This is the code that will be used to add an event listener to the checkboxes in the list of todos.
  • todos[i].completed = checkbox.checked;: This is the code that will be used to update the completed property of the todo based on the checked state of the checkbox.
  • localStorage.setItem("todos", JSON.stringify(todos));: This is the code that will be used to update the local storage with the new completed state of the todo.
  • renderTodos();: This is the code that will be used to render the todos again.
  • const addTodo = () => {: This is the function that will be used to add a new todo.
  • const newTodoText = newTodoInput.value.trim();: This is the code that will be used to get the value of the new todo input.
  • if (newTodoText) {: This is the code that will be used to check if the new todo input is not empty.
  • todos.push({: This is the code that will be used to add a new todo to the todos array.
  • text: newTodoText,: This is the code that will be used to set the text property of the new todo.
  • completed: false: This is the code that will be used to set the completed property of the new todo to false.
  • localStorage.setItem("todos", JSON.stringify(todos));: This is the code that will be used to update the local storage with the new todo.
  • renderTodos();: This is the code that will be used to render the todos again.
  • addTodoButton.addEventListener("click", addTodo);: This is the code that will be used to add an event listener to the addTodoButton.
  • newTodoInput.addEventListener("keydown", (e) => e.key === "Enter" && addTodo());: This is the code that will be used to add an event listener to the newTodoInput.
  • renderTodos();: This is the code that will be used to render the todos again.

The full script

document.addEventListener("DOMContentLoaded", () => {
    const todos = JSON.parse(localStorage.getItem("todos")) || [];
    const todoList = document.getElementById("todoList");
    const newTodoInput = document.getElementById("newTodoInput");
    const addTodoButton = document.getElementById("addTodoButton");

    const renderTodos = () => {
        todoList.innerHTML = todos
            .map(
                (todo, i) => `
        <li class="flex items-center space-x-2 w-full py-2">
          <div class="flex items-center justify-between w-full">
            <div>
              <input type="checkbox" ${todo.completed ? "checked" : ""} class="form-checkbox h-4 w-4 rounded border-gray-300 text-orange-600 focus:ring-orange-600"/>
              <span class="text-lg text-gray-500 ${todo.completed ? "line-through" : ""}">${todo.text}</span>
            </div>
            <button class="text-black hover:text-red-700 focus:outline-none ml-auto">
              <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5">
                <path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z"></path>
              </svg>
            </button>
          </div>
        </li>
      `
            )
            .join("");

        document
            .querySelectorAll('input[type="checkbox"]')
            .forEach((checkbox, i) => {
                checkbox.addEventListener("change", () => {
                    todos[i].completed = checkbox.checked;
                    localStorage.setItem("todos", JSON.stringify(todos));
                    renderTodos();
                });
            });

        document.querySelectorAll("button.text-black").forEach((button, i) => {
            button.addEventListener("click", () => {
                todos.splice(i, 1);
                localStorage.setItem("todos", JSON.stringify(todos));
                renderTodos();
            });
        });
    };

    const addTodo = () => {
        const newTodoText = newTodoInput.value.trim();
        if (newTodoText) {
            todos.push({
                text: newTodoText,
                completed: false
            });
            newTodoInput.value = "";
            localStorage.setItem("todos", JSON.stringify(todos));
            renderTodos();
        }
    };

    addTodoButton.addEventListener("click", addTodo);
    newTodoInput.addEventListener(
        "keydown",
        (e) => e.key === "Enter" && addTodo()
    );

    renderTodos();
});
Enter fullscreen mode Exit fullscreen mode

Conclusion

This is a simple TODO app that can be used to keep track of tasks and prioritize them. It can be used for anything from personal projects to work tasks. Remember that before using this code you will have to make it accessible to your users by adding the necessary HTML and CSS or Tailwind CSS or whatever you are using.

Hope you enjoyed this tutorial and have a great day!

Top comments (0)