In this tutorial, I will teach you how to create a Notes app using HTML5, CSS3, and JavaScript. The complete source code of this JavaScript Notes app is given below.
HTML5, CSS3, JavaScript Notes App Source Code
index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Notes App in JavaScript</title>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Iconscout Link For Icons -->
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.0/css/line.css">
</head>
<body>
<div class="popup-box">
<div class="popup">
<div class="content">
<header>
<p></p>
<i class="uil uil-times"></i>
</header>
<form action="#">
<div class="row title">
<label>Title</label>
<input type="text" spellcheck="false">
</div>
<div class="row description">
<label>Description</label>
<textarea spellcheck="false"></textarea>
</div>
<button></button>
</form>
</div>
</div>
</div>
<div class="wrapper">
<li class="add-box">
<div class="icon"><i class="uil uil-plus"></i></div>
<p>Add new note</p>
</li>
</div>
<script src="script.js"></script>
</body>
</html>script.js
const addBox = document.querySelector(".add-box"),
popupBox = document.querySelector(".popup-box"),
popupTitle = popupBox.querySelector("header p"),
closeIcon = popupBox.querySelector("header i"),
titleTag = popupBox.querySelector("input"),
descTag = popupBox.querySelector("textarea"),
addBtn = popupBox.querySelector("button");
const months = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
const notes = JSON.parse(localStorage.getItem("notes") || "[]");
let isUpdate = false, updateId;
addBox.addEventListener("click", () => {
popupTitle.innerText = "Add a new Note";
addBtn.innerText = "Add Note";
popupBox.classList.add("show");
document.querySelector("body").style.overflow = "hidden";
if(window.innerWidth > 660) titleTag.focus();
});
closeIcon.addEventListener("click", () => {
isUpdate = false;
titleTag.value = descTag.value = "";
popupBox.classList.remove("show");
document.querySelector("body").style.overflow = "auto";
});
function showNotes() {
if(!notes) return;
document.querySelectorAll(".note").forEach(li => li.remove());
notes.forEach((note, id) => {
let filterDesc = note.description.replaceAll("\n", '<br/>');
let liTag = `<li class="note">
<div class="details">
<p>${note.title}</p>
<span>${filterDesc}</span>
</div>
<div class="bottom-content">
<span>${note.date}</span>
<div class="settings">
<i onclick="showMenu(this)" class="uil uil-ellipsis-h"></i>
<ul class="menu">
<li onclick="updateNote(${id}, '${note.title}', '${filterDesc}')"><i class="uil uil-pen"></i>Edit</li>
<li onclick="deleteNote(${id})"><i class="uil uil-trash"></i>Delete</li>
</ul>
</div>
</div>
</li>`;
addBox.insertAdjacentHTML("afterend", liTag);
});
}
showNotes();
function showMenu(elem) {
elem.parentElement.classList.add("show");
document.addEventListener("click", e => {
if(e.target.tagName != "I" || e.target != elem) {
elem.parentElement.classList.remove("show");
}
});
}
function deleteNote(noteId) {
let confirmDel = confirm("Are you sure you want to delete this note?");
if(!confirmDel) return;
notes.splice(noteId, 1);
localStorage.setItem("notes", JSON.stringify(notes));
showNotes();
}
function updateNote(noteId, title, filterDesc) {
let description = filterDesc.replaceAll('<br/>', '\r\n');
updateId = noteId;
isUpdate = true;
addBox.click();
titleTag.value = title;
descTag.value = description;
popupTitle.innerText = "Update a Note";
addBtn.innerText = "Update Note";
}
addBtn.addEventListener("click", e => {
e.preventDefault();
let title = titleTag.value.trim(),
description = descTag.value.trim();
if(title || description) {
let currentDate = new Date(),
month = months[currentDate.getMonth()],
day = currentDate.getDate(),
year = currentDate.getFullYear();
let noteInfo = {title, description, date: `${month} ${day}, ${year}`}
if(!isUpdate) {
notes.push(noteInfo);
} else {
isUpdate = false;
notes[updateId] = noteInfo;
}
localStorage.setItem("notes", JSON.stringify(notes));
showNotes();
closeIcon.click();
}
});style.css
/* Import Google Font - Poppins */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body{
background: #88ABFF;
}
::selection{
color: #fff;
background: #618cf8;
}
.wrapper{
margin: 50px;
display: grid;
gap: 25px;
grid-template-columns: repeat(auto-fill, 265px);
}
.wrapper li{
height: 250px;
list-style: none;
border-radius: 5px;
padding: 15px 20px 20px;
background: #fff;
box-shadow: 0 4px 8px rgba(0,0,0,0.05);
}
.add-box, .icon, .bottom-content,
.popup, header, .settings .menu li{
display: flex;
align-items: center;
justify-content: space-between;
}
.add-box{
cursor: pointer;
flex-direction: column;
justify-content: center;
}
.add-box .icon{
height: 78px;
width: 78px;
color: #88ABFF;
font-size: 40px;
border-radius: 50%;
justify-content: center;
border: 2px dashed #88ABFF;
}
.add-box p{
color: #88ABFF;
font-weight: 500;
margin-top: 20px;
}
.note{
display: flex;
flex-direction: column;
justify-content: space-between;
}
.note .details{
max-height: 165px;
overflow-y: auto;
}
.note .details::-webkit-scrollbar,
.popup textarea::-webkit-scrollbar{
width: 0;
}
.note .details:hover::-webkit-scrollbar,
.popup textarea:hover::-webkit-scrollbar{
width: 5px;
}
.note .details:hover::-webkit-scrollbar-track,
.popup textarea:hover::-webkit-scrollbar-track{
background: #f1f1f1;
border-radius: 25px;
}
.note .details:hover::-webkit-scrollbar-thumb,
.popup textarea:hover::-webkit-scrollbar-thumb{
background: #e6e6e6;
border-radius: 25px;
}
.note p{
font-size: 22px;
font-weight: 500;
}
.note span{
display: block;
color: #575757;
font-size: 16px;
margin-top: 5px;
}
.note .bottom-content{
padding-top: 10px;
border-top: 1px solid #ccc;
}
.bottom-content span{
color: #6D6D6D;
font-size: 14px;
}
.bottom-content .settings{
position: relative;
}
.bottom-content .settings i{
color: #6D6D6D;
cursor: pointer;
font-size: 15px;
}
.settings .menu{
z-index: 1;
bottom: 0;
right: -5px;
padding: 5px 0;
background: #fff;
position: absolute;
border-radius: 4px;
transform: scale(0);
transform-origin: bottom right;
box-shadow: 0 0 6px rgba(0,0,0,0.15);
transition: transform 0.2s ease;
}
.settings.show .menu{
transform: scale(1);
}
.settings .menu li{
height: 25px;
font-size: 16px;
margin-bottom: 2px;
padding: 17px 15px;
cursor: pointer;
box-shadow: none;
border-radius: 0;
justify-content: flex-start;
}
.menu li:last-child{
margin-bottom: 0;
}
.menu li:hover{
background: #f5f5f5;
}
.menu li i{
padding-right: 8px;
}
.popup-box{
position: fixed;
top: 0;
left: 0;
z-index: 2;
height: 100%;
width: 100%;
background: rgba(0,0,0,0.4);
}
.popup-box .popup{
position: absolute;
top: 50%;
left: 50%;
z-index: 3;
width: 100%;
max-width: 400px;
justify-content: center;
transform: translate(-50%, -50%) scale(0.95);
}
.popup-box, .popup{
opacity: 0;
pointer-events: none;
transition: all 0.25s ease;
}
.popup-box.show, .popup-box.show .popup{
opacity: 1;
pointer-events: auto;
}
.popup-box.show .popup{
transform: translate(-50%, -50%) scale(1);
}
.popup .content{
border-radius: 5px;
background: #fff;
width: calc(100% - 15px);
box-shadow: 0 0 15px rgba(0,0,0,0.1);
}
.content header{
padding: 15px 25px;
border-bottom: 1px solid #ccc;
}
.content header p{
font-size: 20px;
font-weight: 500;
}
.content header i{
color: #8b8989;
cursor: pointer;
font-size: 23px;
}
.content form{
margin: 15px 25px 35px;
}
.content form .row{
margin-bottom: 20px;
}
form .row label{
font-size: 18px;
display: block;
margin-bottom: 6px;
}
form :where(input, textarea){
height: 50px;
width: 100%;
outline: none;
font-size: 17px;
padding: 0 15px;
border-radius: 4px;
border: 1px solid #999;
}
form :where(input, textarea):focus{
box-shadow: 0 2px 4px rgba(0,0,0,0.11);
}
form .row textarea{
height: 150px;
resize: none;
padding: 8px 15px;
}
form button{
width: 100%;
height: 50px;
color: #fff;
outline: none;
border: none;
cursor: pointer;
font-size: 17px;
border-radius: 4px;
background: #6A93F8;
}
@media (max-width: 660px){
.wrapper{
margin: 15px;
gap: 15px;
grid-template-columns: repeat(auto-fill, 100%);
}
.popup-box .popup{
max-width: calc(100% - 15px);
}
.bottom-content .settings i{
font-size: 17px;
}
}