Hey, You awesome human ๐,
Introduction
In this tutorial, we are going to see how we can build a To-Do App
using HTML, CSS and JavaScript.
The To-Do App, Will store your todo in your browser's Local Storage
. And provide you with functionalities of Left Click
to toggle complete your ToDo and Right Click
to delete your ToDo.
Below is a live preview of the completed project:
Setting Up the Project
For this project, we will use the VS Code. If you have not installed the Visual Studio Code yet, then click on the link below for download and installation according to your operating system specifications:
For project setup, start by creating a new project folder in VS Code, and inside that project folder, create three empty new files of HTML (index.html), CSS (style.css) and JavaScript (script.js). The Html file is the entry point for our website and contains the HTML code. CSS contains the styling part of our web project and JavaScript contains various functionalities for proper functioning of our web app.
Analysis of the project
As we can see from the screenshot above the page contains a heading element with an input
element for entering todo and ul
element for storing the todo, all of which can be enclosed inside a single outer form
element. If we look outside of the form
element, we can see few instruction enclosed inside small
element.
Let's see the structuring part starting with HTML
later we will see the CSS
applied to each HTML element.
HTML
Get the HTML boilerplate
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
This boilerplate can be easily accessed by typing !
on the first line of the HTML file and pressing tab/enter
key.
Change the title from document
to TO-DO APP
Linking CSS and JavaScript file to the markup
<link rel="stylesheet" href="./style.css">
<script src="./script.js" defer></script>
The defer
attribute is a Boolean attribute. If the defer attribute is set, it specifies that the script is downloaded in parallel to parsing the page, and executed after the page has finished parsing. Note: The defer attribute is only for external scripts (should only be used if the src attribute is present).
Adding favicon to the page
Favicon is one of the most import aspect of any webpage. websites without a favicon looks kinda dull to the end user.
<link rel="shortcut icon"
href="https://cdn-icons-png.flaticon.com/512/1/1560.png"
type="image/x-icon">
Inside
body
Tagbody
tag contains aheading
element with aninput
element for entering todo andul
element for storing the todo, all of which is enclosed inside a single outerform
element. And asmall
element for containing the instructions regarding the usage of the ToDo app along with requiredclass
andid
name.
<h1>todos</h1>
<form action="" id="form">
<input type="text" id="input" class="input" placeholder="Enter your todo" autocomplete="off" />
<ul class="todos" id="todos">
</ul>
</form>
<small class="small">LEFT click to toggle complete <br> RIGHT click to delete</small>
Entire HTML file at a glance
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TO-DO APP</title>
<link rel="shortcut icon" href="https://cdn-icons-png.flaticon.com/512/1/1560.png" type="image/x-icon">
<link rel="stylesheet" href="./style.css">
<script src="./script.js" defer></script>
</head>
<body>
<h1>todos</h1>
<form action="" id="form">
<input type="text" id="input" class="input" placeholder="Enter your todo" autocomplete="off" />
<ul class="todos" id="todos">
</ul>
</form>
<small class="small">LEFT click to toggle complete <br> RIGHT click to delete</small>
</body>
</html>
CSS
Adding required styling
I target the element byclass
name inCSS
and byid
name in script.(mostly)
* {
box-sizing: border-box;
}
body {
background-color: #f5f5f5;
font-family: "Cascadia code";
margin: 0;
display: flex;
align-items: center;
flex-direction: column;
color: #444;
/* justify-content: center; */
}
h1 {
color: rgb(151, 104, 151);
text-align: center;
opacity: 0.4;
font-size: 6rem;
}
form {
/* margin: auto; */
max-width: 100%;
width: 400px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
.input {
font-size: 2rem;
padding: 1rem 2rem;
display: block;
width: 100%;
border: none;
font-family: inherit;
color: #444;
}
.input::placeholder {
color: #b5b5b5;
}
.todos {
background-color: white;
padding: 0;
margin: 0;
list-style-type: none;
}
.todos li {
border-top: 1px solid #e5e5e5;
font-size: 2rem;
cursor: pointer;
padding: 1rem 2rem;
}
.todos li.completed {
text-decoration: line-through;
color: #b5b5b5;
}
.small {
margin-top: 1rem;
color: #b5b5b5;
text-align: center;
}
That's conclude the whole styling part. Now, without any further ado, Let's jump right into JavaScript.
JavaScript
Target all the element with the help of
id
const form = document.getElementById("form"); const input = document.getElementById("input"); const todosUL = document.getElementById("todos");
Function to add ToDo
function addTodo(todo) {
let todoText = input.value;
if (todo) {
todoText = todo.text;
}
if (todoText) {
const todoEl = document.createElement("li");
if (todo && todo.completed) {
todoEl.classList.add("completed");
}
todoEl.innerText = todoText;
todoEl.addEventListener("click", () => {
todoEl.classList.toggle("completed");
updateLS();
});
todoEl.addEventListener("contextmenu", (e) => {
e.preventDefault();
todoEl.remove();
updateLS();
});
todosUL.appendChild(todoEl);
input.value = "";
updateLS();
}
}
form.addEventListener("submit", (e) => {
e.preventDefault();
addTodo();
});
Function for updating the
Local Storage
const todos = JSON.parse(localStorage.getItem("todos"));
if (todos) {
todos.forEach((todo) => {
addTodo(todo);
});
}
function updateLS() {
const todosEl = document.querySelectorAll("li");
const todos = [];
todosEl.forEach((todoEl) => {
todos.push({
text: todoEl.innerText,
completed: todoEl.classList.contains("completed"),
});
});
localStorage.setItem("todos", JSON.stringify(todos));
}
Entire JavaScript file at a glance
console.log("TODOS");
const form = document.getElementById("form");
const input = document.getElementById("input");
const todosUL = document.getElementById("todos");
const todos = JSON.parse(localStorage.getItem("todos"));
if (todos) {
todos.forEach((todo) => {
addTodo(todo);
});
}
form.addEventListener("submit", (e) => {
e.preventDefault();
addTodo();
});
function addTodo(todo) {
let todoText = input.value;
if (todo) {
todoText = todo.text;
}
if (todoText) {
const todoEl = document.createElement("li");
if (todo && todo.completed) {
todoEl.classList.add("completed");
}
todoEl.innerText = todoText;
todoEl.addEventListener("click", () => {
todoEl.classList.toggle("completed");
updateLS();
});
todoEl.addEventListener("contextmenu", (e) => {
e.preventDefault();
todoEl.remove();
updateLS();
});
todosUL.appendChild(todoEl);
input.value = "";
updateLS();
}
}
function updateLS() {
const todosEl = document.querySelectorAll("li");
const todos = [];
todosEl.forEach((todoEl) => {
todos.push({
text: todoEl.innerText,
completed: todoEl.classList.contains("completed"),
});
});
localStorage.setItem("todos", JSON.stringify(todos));
}
Thank you for reading. If you have come this far, don't forget to react to this blog.
If you โค๏ธ My Content! Connect with me on Twitter (abhinav_jha07)
Show your support by buying me a coffee
My other digital presence:
Mail: x3vgi9xr@duck.com
GitHub: akj0712
LinkedIn: abhinavjha07
Telegram: abhinav_kumar_jha
More Content at abhinavjha07.hashnode.dev/
Your feedback is more than welcome