Project: Notes App
Table of Contents + −
In the previous lesson, we built an expense tracker that added up numbers and showed a running total. Now let’s build a notes app that lets you write notes, see them on the page, delete the ones you no longer need, and keep everything saved even after you close the tab.
🎯 What We’ll Build
We will build a small notes app. You type a note into a box, click a button, and the note shows up in a list. Each note has its own delete button. When you reload the page, your notes are still there because we save them in the browser.
This project ties together a lot of what you already know: creating DOM elements, removing them, handling click events, storing data in an array, and saving that data to localStorage.
| Feature | What it does |
| Add a note | Reads the text box and adds a new note to the list |
| Display notes | Shows every note on the page |
| Delete a note | Removes one note by its id |
| Persist notes | Keeps notes saved across page reloads |
🧱 The HTML
We start with a plain HTML page. We need a place to type the note, a button to add it, and an empty container where the notes will appear.
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>Notes App</title> </head> <body> <h1>My Notes</h1>
<textarea id="note-input" placeholder="Write a note..."></textarea> <button id="add-button">Add Note</button>
<div id="notes-container"></div>
<script src="notes-app.js"></script> </body></html>Let’s walk through the parts our JavaScript will reach for:
- The
<textarea id="note-input">is where the user types. Theidgives us a handle to read its text later. - The
<button id="add-button">is what the user clicks to add a note. We attach the “add” action to thisid. - The
<div id="notes-container">starts empty. This is where we insert each note from JavaScript, since the notes themselves are never written in HTML, we create them in code. - The
<script src="notes-app.js">sits at the bottom of thebody, so the elements above it already exist by the time our code runs.
⚙️ The JavaScript
Now the logic. We will keep our notes in an array of objects, where each object has an id and the note text. The id lets us find and delete a specific note later.
First, grab the elements and set up our data.
const noteInput = document.getElementById("note-input");const addButton = document.getElementById("add-button");const notesContainer = document.getElementById("notes-container");
let notes = [];Let’s step through what each line sets up:
noteInputpoints at the textarea, so we can read whatever the user typed.addButtonpoints at the button, so we can run our code when it is clicked.notesContainerpoints at the emptydiv, so we have somewhere to insert the notes.notesstarts as an empty array and holds every note. Each note looks like{ id: 1718000000000, text: "Buy milk" }. We useletbecause we will reassign this array when deleting.
Next, the function that adds a note. It reads the text box, builds a new note object, pushes it into the array, saves, and redraws the list.
function addNote() { const text = noteInput.value.trim();
if (text === "") return; // ignore empty notes
const note = { id: Date.now(), // a unique id based on the current time text: text, };
notes.push(note); noteInput.value = ""; // clear the box
saveNotes(); renderNotes();}We use Date.now() for the id because it returns a different number every time, which makes each id unique. The trim() call removes spaces from the ends, so a note that is only spaces counts as empty.
Now we display the notes. The renderNotes function clears the container, then builds a fresh element for every note in the array using createElement.
function renderNotes() { notesContainer.innerHTML = ""; // clear what's on screen
for (const note of notes) { const noteEl = document.createElement("div"); noteEl.className = "note";
const textEl = document.createElement("p"); textEl.textContent = note.text;
const deleteButton = document.createElement("button"); deleteButton.textContent = "Delete"; deleteButton.addEventListener("click", () => deleteNote(note.id));
noteEl.append(textEl, deleteButton); notesContainer.append(noteEl); }}We clear the container first so we do not draw the same notes twice. For each note we create a div, put the text in a paragraph, and add a delete button. We use textContent instead of innerHTML so the user’s text is shown as plain text and never run as code.
Why pass the id to the click handler?
Each delete button knows the id of its own note because we capture note.id
in the arrow function. When clicked, it tells deleteNote exactly which note
to remove.
Deleting a note means removing it from the array. We use filter to keep every note except the one whose id matches, then save and redraw.
function deleteNote(id) { notes = notes.filter((note) => note.id !== id); saveNotes(); renderNotes();}Now the part that makes notes stick around. localStorage can only store strings, so we turn the array into a string with JSON.stringify when saving, and turn it back into an array with JSON.parse when loading.
function saveNotes() { localStorage.setItem("notes", JSON.stringify(notes));}
function loadNotes() { const saved = localStorage.getItem("notes"); if (saved) { notes = JSON.parse(saved); } renderNotes();}Finally, wire up the button and load any saved notes when the page opens.
addButton.addEventListener("click", addNote);
loadNotes();Here is how the whole flow fits together. When the page loads, loadNotes reads the saved string from localStorage, turns it back into the notes array, and draws it. When you add a note, it goes into the array, gets saved as a string, and the list redraws. When you delete one, filter removes it from the array, we save again, and redraw. The array is the single source of truth, and the screen always mirrors it.
JSON.stringify and JSON.parse
JSON.stringify turns a JavaScript value into a string for storage.
JSON.parse turns that string back into a real array or object. They are
exact opposites, and you will use this pair any time you save data in the
browser.
🚀 Try It Yourself!
You have a working notes app. Here are some upgrades to make it your own.
- Add an edit feature: clicking a note fills the textarea with its text and updates that note instead of adding a new one.
- Add a search box: filter the displayed notes as the user types, matching against each note’s text.
- Add a timestamp: store the time each note was created and show it under the note text.
- Add a clear all button that empties the array and
localStorage.
🧩 What You’ve Learned
- ✅ Storing data as an array of objects with a unique
idandtext - ✅ Creating elements on the page with
createElementandappend - ✅ Deleting an item by its id using
filter - ✅ Handling click events to add and delete notes
- ✅ Saving and loading data with
JSON.stringifyandJSON.parseinlocalStorage
🚀 What’s Next?
You can now build an app that creates, displays, deletes, and saves data. Next we will fetch data from the internet and build a Movie Search App.