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
HTML
x
43
43
1
2
<html lang="en" dir="ltr">
3
<head>
4
<meta charset="utf-8">
5
<title>Notes App in JavaScript</title>
6
<link rel="stylesheet" href="style.css">
7
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8
<!-- Iconscout Link For Icons -->
9
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.0/css/line.css">
10
</head>
11
<body>
12
<div class="popup-box">
13
<div class="popup">
14
<div class="content">
15
<header>
16
<p></p>
17
<i class="uil uil-times"></i>
18
</header>
19
<form action="#">
20
<div class="row title">
21
<label>Title</label>
22
<input type="text" spellcheck="false">
23
</div>
24
<div class="row description">
25
<label>Description</label>
26
<textarea spellcheck="false"></textarea>
27
</div>
28
<button></button>
29
</form>
30
</div>
31
</div>
32
</div>
33
<div class="wrapper">
34
<li class="add-box">
35
<div class="icon"><i class="uil uil-plus"></i></div>
36
<p>Add new note</p>
37
</li>
38
</div>
39
40
<script src="script.js"></script>
41
42
</body>
43
</html>
script.js
JavaScript
1
105
105
1
const addBox = document.querySelector(".add-box"),
2
popupBox = document.querySelector(".popup-box"),
3
popupTitle = popupBox.querySelector("header p"),
4
closeIcon = popupBox.querySelector("header i"),
5
titleTag = popupBox.querySelector("input"),
6
descTag = popupBox.querySelector("textarea"),
7
addBtn = popupBox.querySelector("button");
8
9
const months = ["January", "February", "March", "April", "May", "June", "July",
10
"August", "September", "October", "November", "December"];
11
const notes = JSON.parse(localStorage.getItem("notes") || "[]");
12
let isUpdate = false, updateId;
13
14
addBox.addEventListener("click", () => {
15
popupTitle.innerText = "Add a new Note";
16
addBtn.innerText = "Add Note";
17
popupBox.classList.add("show");
18
document.querySelector("body").style.overflow = "hidden";
19
if(window.innerWidth > 660) titleTag.focus();
20
});
21
22
closeIcon.addEventListener("click", () => {
23
isUpdate = false;
24
titleTag.value = descTag.value = "";
25
popupBox.classList.remove("show");
26
document.querySelector("body").style.overflow = "auto";
27
});
28
29
function showNotes() {
30
if(!notes) return;
31
document.querySelectorAll(".note").forEach(li => li.remove());
32
notes.forEach((note, id) => {
33
let filterDesc = note.description.replaceAll("\n", '<br/>');
34
let liTag = `<li class="note">
35
<div class="details">
36
<p>${note.title}</p>
37
<span>${filterDesc}</span>
38
</div>
39
<div class="bottom-content">
40
<span>${note.date}</span>
41
<div class="settings">
42
<i onclick="showMenu(this)" class="uil uil-ellipsis-h"></i>
43
<ul class="menu">
44
<li onclick="updateNote(${id}, '${note.title}', '${filterDesc}')"><i class="uil uil-pen"></i>Edit</li>
45
<li onclick="deleteNote(${id})"><i class="uil uil-trash"></i>Delete</li>
46
</ul>
47
</div>
48
</div>
49
</li>`;
50
addBox.insertAdjacentHTML("afterend", liTag);
51
});
52
}
53
showNotes();
54
55
function showMenu(elem) {
56
elem.parentElement.classList.add("show");
57
document.addEventListener("click", e => {
58
if(e.target.tagName != "I" || e.target != elem) {
59
elem.parentElement.classList.remove("show");
60
}
61
});
62
}
63
64
function deleteNote(noteId) {
65
let confirmDel = confirm("Are you sure you want to delete this note?");
66
if(!confirmDel) return;
67
notes.splice(noteId, 1);
68
localStorage.setItem("notes", JSON.stringify(notes));
69
showNotes();
70
}
71
72
function updateNote(noteId, title, filterDesc) {
73
let description = filterDesc.replaceAll('<br/>', '\r\n');
74
updateId = noteId;
75
isUpdate = true;
76
addBox.click();
77
titleTag.value = title;
78
descTag.value = description;
79
popupTitle.innerText = "Update a Note";
80
addBtn.innerText = "Update Note";
81
}
82
83
addBtn.addEventListener("click", e => {
84
e.preventDefault();
85
let title = titleTag.value.trim(),
86
description = descTag.value.trim();
87
88
if(title || description) {
89
let currentDate = new Date(),
90
month = months[currentDate.getMonth()],
91
day = currentDate.getDate(),
92
year = currentDate.getFullYear();
93
94
let noteInfo = {title, description, date: `${month} ${day}, ${year}`}
95
if(!isUpdate) {
96
notes.push(noteInfo);
97
} else {
98
isUpdate = false;
99
notes[updateId] = noteInfo;
100
}
101
localStorage.setItem("notes", JSON.stringify(notes));
102
showNotes();
103
closeIcon.click();
104
}
105
});
style.css
CSS
1
246
246
1
/* Import Google Font - Poppins */
2
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');
3
*{
4
margin: 0;
5
padding: 0;
6
box-sizing: border-box;
7
font-family: 'Poppins', sans-serif;
8
}
9
body{
10
background: #88ABFF;
11
}
12
::selection{
13
color: #fff;
14
background: #618cf8;
15
}
16
.wrapper{
17
margin: 50px;
18
display: grid;
19
gap: 25px;
20
grid-template-columns: repeat(auto-fill, 265px);
21
}
22
.wrapper li{
23
height: 250px;
24
list-style: none;
25
border-radius: 5px;
26
padding: 15px 20px 20px;
27
background: #fff;
28
box-shadow: 0 4px 8px rgba(0,0,0,0.05);
29
}
30
.add-box, .icon, .bottom-content,
31
.popup, header, .settings .menu li{
32
display: flex;
33
align-items: center;
34
justify-content: space-between;
35
}
36
.add-box{
37
cursor: pointer;
38
flex-direction: column;
39
justify-content: center;
40
}
41
.add-box .icon{
42
height: 78px;
43
width: 78px;
44
color: #88ABFF;
45
font-size: 40px;
46
border-radius: 50%;
47
justify-content: center;
48
border: 2px dashed #88ABFF;
49
}
50
.add-box p{
51
color: #88ABFF;
52
font-weight: 500;
53
margin-top: 20px;
54
}
55
.note{
56
display: flex;
57
flex-direction: column;
58
justify-content: space-between;
59
}
60
.note .details{
61
max-height: 165px;
62
overflow-y: auto;
63
}
64
.note .details::scrollbar,
65
.popup textarea::scrollbar{
66
width: 0;
67
}
68
.note .details:hover::scrollbar,
69
.popup textarea:hover::scrollbar{
70
width: 5px;
71
}
72
.note .details:hover::scrollbar-track,
73
.popup textarea:hover::scrollbar-track{
74
background: #f1f1f1;
75
border-radius: 25px;
76
}
77
.note .details:hover::scrollbar-thumb,
78
.popup textarea:hover::scrollbar-thumb{
79
background: #e6e6e6;
80
border-radius: 25px;
81
}
82
.note p{
83
font-size: 22px;
84
font-weight: 500;
85
}
86
.note span{
87
display: block;
88
color: #575757;
89
font-size: 16px;
90
margin-top: 5px;
91
}
92
.note .bottom-content{
93
padding-top: 10px;
94
border-top: 1px solid #ccc;
95
}
96
.bottom-content span{
97
color: #6D6D6D;
98
font-size: 14px;
99
}
100
.bottom-content .settings{
101
position: relative;
102
}
103
.bottom-content .settings i{
104
color: #6D6D6D;
105
cursor: pointer;
106
font-size: 15px;
107
}
108
.settings .menu{
109
z-index: 1;
110
bottom: 0;
111
right: -5px;
112
padding: 5px 0;
113
background: #fff;
114
position: absolute;
115
border-radius: 4px;
116
transform: scale(0);
117
transform-origin: bottom right;
118
box-shadow: 0 0 6px rgba(0,0,0,0.15);
119
transition: transform 0.2s ease;
120
}
121
.settings.show .menu{
122
transform: scale(1);
123
}
124
.settings .menu li{
125
height: 25px;
126
font-size: 16px;
127
margin-bottom: 2px;
128
padding: 17px 15px;
129
cursor: pointer;
130
box-shadow: none;
131
border-radius: 0;
132
justify-content: flex-start;
133
}
134
.menu li:last-child{
135
margin-bottom: 0;
136
}
137
.menu li:hover{
138
background: #f5f5f5;
139
}
140
.menu li i{
141
padding-right: 8px;
142
}
143
144
.popup-box{
145
position: fixed;
146
top: 0;
147
left: 0;
148
z-index: 2;
149
height: 100%;
150
width: 100%;
151
background: rgba(0,0,0,0.4);
152
}
153
.popup-box .popup{
154
position: absolute;
155
top: 50%;
156
left: 50%;
157
z-index: 3;
158
width: 100%;
159
max-width: 400px;
160
justify-content: center;
161
transform: translate(-50%, -50%) scale(0.95);
162
}
163
.popup-box, .popup{
164
opacity: 0;
165
pointer-events: none;
166
transition: all 0.25s ease;
167
}
168
.popup-box.show, .popup-box.show .popup{
169
opacity: 1;
170
pointer-events: auto;
171
}
172
.popup-box.show .popup{
173
transform: translate(-50%, -50%) scale(1);
174
}
175
.popup .content{
176
border-radius: 5px;
177
background: #fff;
178
width: calc(100% - 15px);
179
box-shadow: 0 0 15px rgba(0,0,0,0.1);
180
}
181
.content header{
182
padding: 15px 25px;
183
border-bottom: 1px solid #ccc;
184
}
185
.content header p{
186
font-size: 20px;
187
font-weight: 500;
188
}
189
.content header i{
190
color: #8b8989;
191
cursor: pointer;
192
font-size: 23px;
193
}
194
.content form{
195
margin: 15px 25px 35px;
196
}
197
.content form .row{
198
margin-bottom: 20px;
199
}
200
form .row label{
201
font-size: 18px;
202
display: block;
203
margin-bottom: 6px;
204
}
205
form :where(input, textarea){
206
height: 50px;
207
width: 100%;
208
outline: none;
209
font-size: 17px;
210
padding: 0 15px;
211
border-radius: 4px;
212
border: 1px solid #999;
213
}
214
form :where(input, textarea):focus{
215
box-shadow: 0 2px 4px rgba(0,0,0,0.11);
216
}
217
form .row textarea{
218
height: 150px;
219
resize: none;
220
padding: 8px 15px;
221
}
222
form button{
223
width: 100%;
224
height: 50px;
225
color: #fff;
226
outline: none;
227
border: none;
228
cursor: pointer;
229
font-size: 17px;
230
border-radius: 4px;
231
background: #6A93F8;
232
}
233
234
@media (max-width: 660px){
235
.wrapper{
236
margin: 15px;
237
gap: 15px;
238
grid-template-columns: repeat(auto-fill, 100%);
239
}
240
.popup-box .popup{
241
max-width: calc(100% - 15px);
242
}
243
.bottom-content .settings i{
244
font-size: 17px;
245
}
246
}