Let’s say you are building a web app where users will be able to work with textual data or media such as images. You want to allow them to write text that should be accessible even after a page refresh or browser restart. Before the Web Storage API, you would have to store information on the backend and reload it again on the client side when needed. This is still the way to go if you want the information to be available on all browsers or devices.
However, if the information you want to keep across page refreshes or browser restarts needs to be accessible only on the same browser, the Web Storage API is a much more suitable tool.
There are two types of web storage implementations called localStorage
And sessionStorage
. As you may have guessed from the name, sessionStorage
retains information for a single session e localStorage
keep your data even after restarting the browser.
In this tutorial we will learn all the basics of the Web Storage API and see how we can use local storage and session storage to our advantage.
Difference between local storage and session storage
Before delving into the API, let’s learn the basic differences between local storage and session storage.
-
localStorage
it doesn’t even expire when the browser is restarted whilesessionStorage
it only lasts until a page is refreshed. -
localStorage
it is shared among multiple tabs and windows that have the same origin. On the other hand,sessionStorage
it will be different for each tab that has loaded the same web page.
An individual web page or document can have its own localStorage
as well as sessionStorage
object. However, both will be independent of each other.
Available web archiving methods and properties
There are five methods for both localStorage
And sessionStorage
.
You can use the setItem(key, value)
method to store some information in the storage object as a key/value pair. If the key already exists, this method will update its value. Note that this method requires both the key and the value for a string.
You can use the getItem(key)
method for retrieving the information stored for a particular key. This method will come back null
if the passed key does not exist.
Let’s say you want to remove some information from your file localStorage
or sessionStorage
in this case, you can use the removeItem(key)
method and pass the relevant key name to remove a key and its value from the archive.
Instead of removing keys from your storage one at a time, you can also use the file clear()
method to erase all keys at once.
There is also a key(index)
method that takes an integer as the index of the key and returns you the name of the key at that particular index. The important thing to remember here is that the order of the keys is defined by the user agent.
Finally, there is a length
property that can be used to get the number of data items stored in a given storage object.
You can use the length
property in combination with the key()
method and the getItem()
method to access the values of all keys in your localSotrage
or sessionStorage
.
Here are some examples of using all of these methods:
1 |
/* Save some key-value pairs */
|
2 |
localStorage.setItem("artist", "Monty Shokeen"); |
3 |
localStorage.setItem("website", "tutsplus.com"); |
4 |
localStorage.setItem("font", "Righteous"); |
5 |
localStorage.setItem("stroke_width", "4"); |
6 |
localStorage.setItem("color", "#FF5722"); |
7 |
|
8 |
/* Access stored values */
|
9 |
console.log(localStorage.getItem("color")); |
10 |
// Outputs: #FF5722
|
11 |
|
12 |
console.log(localStorage.getItem("stroke_width")); |
13 |
// Outputs: 4
|
14 |
|
15 |
/* Iterate over keys */
|
16 |
for (let i = 0; i < localStorage.length; i++) { |
17 |
console.log(`${localStorage.key(i)} : ${localStorage.getItem(localStorage.key(i))}`); |
18 |
}
|
19 |
/*
|
20 |
stroke_width : 4
|
21 |
font : Righteous
|
22 |
website : tutsplus.com
|
23 |
color : #FF5722
|
24 |
artist : Monty Shokeen
|
25 |
*/
|
26 |
|
27 |
/* Removing keys from storage */
|
28 |
localStorage.removeItem("website"); |
29 |
localStorage.getItem("website"); |
30 |
// Outputs: null
|
Practical application of local storage
Let’s do something practical with all the knowledge we have acquired. We will create a simple drawing application where users will be able to save their data to local storage for future retrieval.
Our drawing application will be very simple. We will have a canvas where users can draw concentric circles of random radius. The minimum and maximum value of the radius will be determined by the input fields filled in by them. We’ll also have a button to clear the canvas once we’ve drawn too many circles. Here is our markup:
1 |
<canvas id="canvas" width="810" height="400"></canvas> |
2 |
<form>
|
3 |
<label for="min-rad">Min. Radius</label> |
4 |
<input type="number" name="min-rad" id="min-rad" min="4"></input> |
5 |
<br>
|
6 |
<label for="max-rad">Max. Radius</label> |
7 |
<input type="number" name="max-rad" id="max-rad" min="20"></input> |
8 |
<br>
|
9 |
<button type="button" id="clear">Clear Canvas</button> |
10 |
</form>
|
We will store three pieces of information in our local memory: the minimum radius, the maximum radius and the state of the canvas. Remember that local storage can only store information such as strings. The value of the input fields can be automatically converted into strings. However, we will have to use the toDataURL()
method to get the state of our canvas as a string. This method will return a string containing the URL of the requested data.
We will attach event listeners to all web page elements. A mousedown
event listener for the canvas. A change
event listener for input elements ea click
event listener for buttons. We start with some initialization code and event listeners for the form fields.
1 |
const canvas = document.getElementById("canvas"); |
2 |
const ctx = canvas.getContext("2d"); |
3 |
|
4 |
const minElem = document.querySelector("input#min-rad"); |
5 |
const maxElem = document.querySelector("input#max-rad"); |
6 |
const clearBtn = document.querySelector("button#clear"); |
7 |
|
8 |
let min_radius = 10; |
9 |
let max_radius = 30; |
10 |
|
11 |
minElem.addEventListener("change", function(event) { |
12 |
min_radius = parseInt(event.target.value); |
13 |
localStorage.setItem("min-radius", min_radius); |
14 |
});
|
15 |
|
16 |
maxElem.addEventListener("change", function(event) { |
17 |
max_radius = parseInt(event.target.value); |
18 |
localStorage.setItem("max-radius", max_radius); |
19 |
});
|
20 |
|
21 |
clearBtn.addEventListener("click", function(event) { |
22 |
ctx.clearRect(0, 0, canvas.width, canvas.height); |
23 |
|
24 |
let image_data = canvas.toDataURL(); |
25 |
localStorage.setItem("image-data", image_data); |
26 |
});
|
By default, we keep the minimum and maximum radius values set to 10 and 30 pixels, respectively. The change event listener for the minimum and maximum radius input fields will parse the value of the inputs and then store those values in local storage.
Inside the click event listener callback for our button, we first cleared the canvas and then saved this cleared state to our local storage using the toDataUrl()
method.
Here is the code that listens to the file mousedown
event on our canvas.
1 |
canvas.addEventListener('mousedown', function(event) { |
2 |
const canvas_rect = event.target.getBoundingClientRect(); |
3 |
const pos_x = event.clientX - canvas_rect.left; |
4 |
const pos_y = event.clientY - canvas_rect.top; |
5 |
|
6 |
for(let i = 0; i < 10; i++) { |
7 |
let radius = min_radius + Math.floor(Math.random()*(max_radius - min_radius)); |
8 |
ctx.beginPath(); |
9 |
ctx.arc(pos_x, pos_y, radius, 0, 2 * Math.PI); |
10 |
ctx.stroke(); |
11 |
}
|
12 |
|
13 |
let image_data = canvas.toDataURL(); |
14 |
localStorage.setItem("image-data", image_data); |
15 |
});
|
Let’s analyze it. We start by calculating the exact location where users clicked on the canvas. This is determined by subtracting the value of left
properties of the bounding box of the canvas from the x coordinate of the clicked position. We do the same thing to get the vertical position of the click.
Next, we create a file for
loop to draw 10 concentric circles on the canvas. The radius is set to a random value subject to minimum and maximum constraints. Finally, just like the click listener for the button, we save the state of the canvas to our local storage. This happens with every click so you can stay up to date with the latest state of the canvas.
The only thing left for us to do now is restore the values from local storage to use for reloads or reboots. We do this with the following code:
1 |
window.addEventListener("DOMContentLoaded", (event) => { |
2 |
if (localStorage.getItem("image-data")) { |
3 |
var img = new Image(); |
4 |
img.onload = function () { |
5 |
ctx.drawImage(img, 0, 0); |
6 |
};
|
7 |
img.src = localStorage.getItem("image-data"); |
8 |
}
|
9 |
|
10 |
if (localStorage.getItem("min-radius")) { |
11 |
min_radius = parseInt(localStorage.getItem("min-radius")); |
12 |
}
|
13 |
|
14 |
if (localStorage.getItem("max-radius")) { |
15 |
max_radius = parseInt(localStorage.getItem("max-radius")); |
16 |
}
|
17 |
|
18 |
minElem.value = min_radius; |
19 |
maxElem.value = max_radius; |
20 |
});
|
The trickiest section here is restoring the image data from local storage to the canvas. We do this by first creating a new instance of HTMLImageElement
and then listening to his onload
event to draw the loaded image on canvas.
The following CodePen demo will show you our drawing application in action. Try clicking on the canvas to draw some circles or set the radius to values you like first.
Right now, we are using localStorage
in our tutorial, which means that our data will be safe even if the browser restarts. You can try replacing it with sessionStorage
to keep the information only during page updates.
Final thoughts
In this tutorial, we’ve covered the basics of localStorage
And sessionStorage
in javascript. You should now be able to store and retrieve information in browser memory using the web storage API. This API has many applications as we have seen while building our drawing app here. You can also use it to implement the functionality of saving content in a local text editor.