May 30, 2019
•Last updated November 5, 2023
How to use Local Storage with JavaScript
It has been a bit since I did another Let's Build: With JavaScript so I'm back with a new one focusing on using Local Storage.
As a precursor to this tutorial I highly recommend not using local storage for comment data as I'm about to show you but rather more for small key-value assignments. For example, say you display a notification prompt, email subscription prompt, or alert of some kind on your site. You can hook into the browsers local storage API to save whether or not a given user wants to see these things as they display on your site.
That all could take place with a click event with JavaScript.
This tutorial goes one step further to show a proof of concept around adding a new comment to an existing comment feed. This in no way is complete but gives you an overview of how to both append new data to the DOM as well as store that data with local storage.
I invite you to extend this code to allow the commenter to delete their comments from local storage as well.
The Markup
I'll be using some dummy data for starters. We will create a comment feed with one comment already in view. Below the feed will be a new comment form that once submitted will create and insert the value of the new comment on the page. This will also hook into local storage to save the persisted data so when the commenter navigates away from the page and comes back, the data is still present.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Let's Build with JavaScript - Local Storage Comments</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div class="comment-container">
<h3 class="comment-container-title">Comments</h3>
<div class="comments">
<div class="comment flex items-start justify-start">
<img
class="comment-avatar"
src="https://secure.gravatar.com/avatar/d1f5ca0d7e625f334c5186e112b77ebd"
/>
<div class="flex-1">
<h3 class="comment-author">Andy Leverenz</h3>
<p class="comment-body">First comment of some type!</p>
</div>
</div>
</div>
<div class="comment comment-new flex items-start justify-start">
<img
class="comment-avatar"
src="https://secure.gravatar.com/avatar/d1f5ca0d7e625f334c5186e112b77ebd"
/>
<div class="flex-1">
<h3 class="comment-author">Andy Leverenz</h3>
<form action="#" class="comment-form">
<textarea
placeholder="Add a comment"
class="comment-input"
></textarea>
<input type="submit" class="comment-submit" value="Reply" />
</form>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
The CSS
We ought to make the form and comment feed more presentable. In doing so I created the following CSS.
* {
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 1rem;
line-height: 1;
}
.flex {
display: flex;
}
.flex-1 {
flex: 1;
}
.items-start {
align-items: start;
}
.justify-start {
justify-content: flex-start;
}
.comment-container {
border-radius: 8px;
border: 1px solid #e2e2e2;
margin: 3rem auto;
max-width: 600px;
min-height: 200px;
}
.comment-container-title {
background: #f8f8f8;
border-bottom: 1px solid #ebebeb;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
color: #2d3748;
margin-top: 0;
padding: 1rem 2rem;
}
.comment {
margin-top: 1rem;
padding: 1rem 2rem;
}
.comment-new {
border-top: 1px solid #ebebeb;
margin: 1rem 0;
padding-top: 2rem;
}
.comment-avatar {
border-radius: 50%;
height: 48px;
margin-right: 1rem;
width: 48px;
}
.comment-author {
font-size: 1rem;
margin-bottom: 0.5rem;
margin-top: 0;
}
.comment-body {
color: #4a5568;
line-height: 1.4;
margin: 0;
padding-right: 1rem;
}
.comment-input {
border-radius: 8px;
border: 1px solid #dddd;
box-sizing: border-box;
color: #4a5568;
font-size: 1rem;
line-height: 1.4;
padding: 0.8rem;
width: 100%;
}
.comment-input:focus {
border-color: #5c6ac4;
outline: none;
}
.comment-submit {
background: #5c6ac4;
border-radius: 4px;
border: none;
color: white;
cursor: pointer;
font-size: 12px;
letter-spacing: 0.05rem;
margin-top: 0.5rem;
padding: 10px 16px;
text-transform: uppercase;
}
.comment-submit:hover,
.comment-submit:focus {
filter: brightness(110%);
}
JavaScript
Finally, we make it all work. Even though there is a form element on the page I want to disable its default action. We can do that by adding an event listener on the Reply
button. That button will also kick off the process of adding the newly created comment to the DOM itself.
From there we adhere to the template using ES6 string literals and pass in the appropriate data. The data could be much more dynamic but to do that we'd need to either leverage a remote API or a datastore. I commonly work with Ruby on Rails so I would probably reach for the latter and output it somewhere in the markup to later grab with JavaScript directly.
In the end, my code looks like the following. I've added comments to be more clear.
const submit = document.querySelector('.comment-submit');
const commentList = document.querySelector('.comments');
const commentInput = document.querySelector('.comment-input');
function template(data) {
commentList.insertAdjacentHTML("beforeend", `
<div class="comment flex items-start justify-start">
<img class="comment-avatar" src="${data.avatar}" />
<div class="flex-1">
<h3 class="comment-author">${data.author}</h3>
<p class="comment-body">${data.comment}</p>
</div>
</div>
</div>`);
}
function appendComment (event) {
const data = {
avatar: "https://secure.gravatar.com/avatar/d1f5ca0d7e625f334c5186e112b77ebd",
comment: commentInput.value,
author: "Andy Leverenz"
};
event.preventDefault();
// If the value is nothing just return
if (commentInput.value.length < 1) return;
// Insert new template into DOM
template(data);
// Reset textrea value
commentInput.value = "";
// Save the list to localStorage
localStorage.setItem('commentListing', commentList.innerHTML);
}
submit.addEventListener('click', appendComment, false)
// Check for saved wishlist items
const saved = localStorage.getItem('commentListing');
// If there are any saved items, update our list
if (saved) {
commentList.innerHTML = saved;
}
Again I invite you to extend this further. Maybe see if you can figure out a way to delete a comment from local storage as well. You might be able to call localStorage.removeItem('my-item, <string>)
the same way it was created ;)
The series so far
- Letβs Build: With JavaScript β DIY Dropdowns and Responsive Menus
- Let's Build: With JavaScript - Broadcast Bar with Cookies
- Let's Build: With JavaScript - Sticky Nav
- Let's Build: With JavaScript - Dynamic Tabs
- Let's Build: With JavaScript - Modals
- Let's Build: With JavaScript - HTML5 Video Player
- Let's Build: With JavaScript - Accordions
- Let's Build: With JavaScript - Skeleton Screen Effect
- Let's Build: With JavaScript - How to Code an Off-Canvas Menu - Let's Build: With JavaScript
- Let's Build: With JavaScript - Show More β Show Less Toggle with JavaScript
Categories
Collection
Part of the Let's Build: With JavaScript collection
Products and courses
-
Hello Hotwire
A course on Hotwire + Ruby on Rails.
-
Hello Rails
A course for newcomers to Ruby on Rails.
-
Rails UI
UI templates and components for Rails.