Build a Notes App using JavaScript and Local Storage
Learn how to build a fully functional Notes App using Vanilla JavaScript and Local Storage to save data persistently.
Table of Contents
In this tutorial, we will learn how to build a fully functional Notes App using Vanilla JavaScript. This app will allow users to add new notes, edit existing ones, and delete them. We will use the browserโs Local Storage API to save the notes persistently, so they are not lost when the page is refreshed.
HTML Structure
First, letโs create the basic structure of our Notes App. We need a container for the app, a header with an โAdd Noteโ button, and a grid to display the notes.
<div class="app-container">
<div class="header">
<h1>My Notes</h1>
<button class="add-btn" id="add-note">+ Add Note</button>
</div>
<div class="notes-grid" id="notes-grid">
<!-- Notes will be inserted here dynamically -->
</div>
</div>
CSS Styling
Next, we will style our app to give it a clean and modern look. We will use CSS Grid to display the notes in a responsive layout and add hover effects for a premium feel.
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Inter', sans-serif;
}
body {
background-color: #f3f4f6;
display: flex;
justify-content: center;
padding: 2rem;
min-height: 100vh;
}
.app-container {
width: 100%;
max-width: 900px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.header h1 {
font-size: 2rem;
color: #111827;
}
.add-btn {
background: #04AA6D;
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 6px -1px rgba(4, 170, 109, 0.2);
transition: all 0.2s ease;
}
.add-btn:hover {
background: #038a58;
transform: translateY(-2px);
}
.notes-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1.5rem;
}
.note {
background: white;
border-radius: 12px;
padding: 1.2rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.05);
position: relative;
transition: all 0.3s ease;
display: flex;
flex-direction: column;
}
.note:hover {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
transform: translateY(-5px);
}
.note textarea {
width: 100%;
border: none;
resize: none;
outline: none;
background: transparent;
color: #374151;
font-size: 1rem;
line-height: 1.5;
}
.note .note-title {
font-weight: 600;
font-size: 1.2rem;
margin-bottom: 0.5rem;
color: #1f2937;
}
.note .note-body {
flex-grow: 1;
min-height: 120px;
}
.delete-btn {
position: absolute;
bottom: 15px;
right: 15px;
background: #ef4444;
color: white;
border: none;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.2s ease;
}
.note:hover .delete-btn {
opacity: 1;
}
.delete-btn:hover {
background: #dc2626;
}
JavaScript Logic
Finally, we will add the JavaScript logic to handle creating, updating, deleting, and storing the notes using localStorage.
const notesGrid = document.getElementById('notes-grid');
const addNoteBtn = document.getElementById('add-note');
// Load notes from local storage
const getNotes = () => JSON.parse(localStorage.getItem('notes-app') || '[]');
// Save notes to local storage
const saveNotes = (notes) => localStorage.setItem('notes-app', JSON.stringify(notes));
// Create a note element
const createNoteElement = (id, title, body) => {
const noteDiv = document.createElement('div');
noteDiv.classList.add('note');
const titleInput = document.createElement('textarea');
titleInput.classList.add('note-title');
titleInput.placeholder = 'Note Title';
titleInput.value = title;
titleInput.rows = 1;
const bodyInput = document.createElement('textarea');
bodyInput.classList.add('note-body');
bodyInput.placeholder = 'Type your note here...';
bodyInput.value = body;
const deleteBtn = document.createElement('button');
deleteBtn.classList.add('delete-btn');
deleteBtn.innerHTML = '๐๏ธ';
// Event listeners for updating note
const updateNote = () => {
const notes = getNotes();
const note = notes.find(n => n.id === id);
if (note) {
note.title = titleInput.value;
note.body = bodyInput.value;
saveNotes(notes);
}
};
titleInput.addEventListener('input', updateNote);
bodyInput.addEventListener('input', updateNote);
deleteBtn.addEventListener('click', () => {
const confirmDelete = confirm('Are you sure you want to delete this note?');
if (confirmDelete) {
const notes = getNotes().filter(n => n.id !== id);
saveNotes(notes);
notesGrid.removeChild(noteDiv);
}
});
noteDiv.appendChild(titleInput);
noteDiv.appendChild(bodyInput);
noteDiv.appendChild(deleteBtn);
return noteDiv;
};
// Render all notes
const renderNotes = () => {
notesGrid.innerHTML = '';
const notes = getNotes();
notes.forEach(note => {
const noteEl = createNoteElement(note.id, note.title, note.body);
notesGrid.appendChild(noteEl);
});
};
// Add new note
addNoteBtn.addEventListener('click', () => {
const notes = getNotes();
const newNote = {
id: Date.now().toString(),
title: '',
body: ''
};
notes.unshift(newNote); // Add to the top
saveNotes(notes);
// Render the new note at the beginning
const noteEl = createNoteElement(newNote.id, newNote.title, newNote.body);
notesGrid.prepend(noteEl);
});
// Initial render
renderNotes();
With this, you have successfully built a Notes App! The data will persist across browser reloads, providing a seamless user experience. You can check out the live demo using the button above.