How to save persistent data to the user's browser with localStorage

How to save persistent data to the user's browser with localStorage

ยท

7 min read

In this tutorial, I'll teach you how to save persistent data to the user's browser using the localStorage object, which is part of the HTML Web Storage API. I'll cover some simple use cases, including saving a game hiscore, some to-do list data and the user's light/dark mode preference.

I first came across localStorage when I was building a to-do list app โ€” I guess this is a rite of passage when you start learning front-end development! But a to-do list app is not of much use if you can't store the user's list somehow! Likewise, I'd also made some simple games where I wanted to be able to save the user's best score.

Thanks to the Web Storage API, storing persistent data in the user's browser is actually very quick, simple and reliable.

What is the Web Storage API?

The Web Storage API was introduced in HTML5 and is fully supported across all major desktop and mobile browsers. This API allows you to store data in a key-value pair format directly in the user's browser. Typically, you can store around 5MB per origin but this varies between browsers. Don't worry, I'll discuss "origin" in the next section.

The Web Storage API comprises two storage objects sessionStorage and localStorage. In this tutorial, I'll be focusing on localStorage but they both work in the same way and use the same methods and properties. The key difference between the two is data persistence.

For sessionStorage, stored data survives a page refresh but is cleared on tab or browser closure. True to its name, the data only persists for the session.

In contrast, data stored in localStorage has no expiration date and persists across page refreshes, tab closures and browser and OS restarts. So, the data is more-or-less permanent. You can only delete this data using JavaScript, the browser dev tools or by clearing the browser cache.

It's worth mentioning that the Web Storage API is different to using cookies. For a starter, cookies can only store a measly 4kB of data. But the main difference is that Web Storage is client-side only. No data is sent server-side, you can only control it through JavaScript and the storage is bound to the origin.

So, localStorage generally has no performance impact but if you want to send data server-side, then cookies may be a better option.

Cookies are also delicious, especially with coffee ๐Ÿชโ˜•

What does origin mean?

Origin kinda means website but, more specifically, it means per domain, protocol and port.

So, for example:

  • https://mydomain.com/home and https://mydomain.com/about have the same domain and protocol, so would share the same storage object in the user's browser
  • https://mydomain.com/home and http://mydomain.com/home use different protocols, so would use separate storage objects
  • https://mydomain.com/home and https://anotherdomain.com/home are on different domains, so would also use separate storage objects
  • http://localhost:3000 and http://localhost:4000 are on different ports, so again would use separate storage objects

How to use localStorage

As I mentioned earlier, storing and retrieving data from localStorage is quick and simple. You just call the setItem() and getItem() methods on the localStorage object.

Using setItem() and getItem()

To store data in the browser, you call the setItem() method and pass in the key (a name) and value (your data) as arguments:

localStorage.setItem('myKey', 'random value')
localStorage.setItem('fav drink', 'coffee')

You can then retrieve this data by calling the getItem() method and passing in the name of the key you wish to access:

const myValue = localStorage.getItem('myKey')
console.log(myValue) // logs: 'random value'

const myFavDrink = localStorage.getItem('fav drink')
console.log(myFavDrink) // logs: 'coffee'

Existing keys will be overwritten, which allows you to easily update the values stored in localStorage:

localStorage.setItem('fav drink', 'black coffee')
console.log(localStorage.getItem('fav drink')) // logs: 'black coffee'

You can also view the contents of the localStorage object with your browser dev tools. For example, you can find it under the Application tab in Chrome and the Storage tab in Firefox.

Here is a screenshot of what localStorage looks like in Firefox, where you can see all the key-value pairs I've created in this article: localStorage in dev tools.png

Using object dot notation

An even simpler way to set and retrieve data is using object dot notation:

localStorage.username = 'Bobby McBobFace'
console.log(localStorage.username) // logs: 'Bobby McBobFace'

However, using object dot notation can potentially cause issues if the key name is derived from user input. Say, for example, the user provides a key name of length, which is a built-in property of localStorage:

localStorage.length = 'very long'
console.log(localStorage.getItem('length')) // logs: null

localStorage.setItem('length', 'very long')
console.log(localStorage.getItem('length')) // logs: 'length'
console.log(localStorage.length) // logs: 3

So, localStorage.length is returning the number of stored items in the object!

Obviously, this also applies to other key names that clash with localStorage properties/methods but there's not that many of them (see next section) so it's unlikely to be a problem in most cases.

Another drawback of using dot notation for storing and modifying values is that the storage event won't fire. The storage event allows different tabs/windows from the same origin to communicate via event listeners but I won't go into this here!

Methods and properties

Both localStorage and sessionStorage also have access to the following methods, which you can call using standard dot notation:

  • removeItem(key) โ€” deletes the specified key-value pair, e.g. localStorage.removeItem('fav drink')
  • clear()โ€” deletes all key-value pairs for the origin, so be careful!
  • length โ€” returns the number of key-value pairs (i.e. stored items) for the origin
  • key(index) โ€” returns the value for a given index, e.g. localStorage.key(3)

It's worth noting here that localStorage and sessionStorage are actually array-like objects as opposed to standard JavaScript objects, hence why they have indexed properties and a length.

Strings only!

You may have spotted that all my examples so far have used strings as a value! Well, that's because both keys and values must be strings. In fact, all primitive data types will automatically be converted to a string and you will need to covert arrays and objects to a string before saving to localStorage.

In the use case examples in the next section, I'll demonstrate how to store and retrieve several other data types.

Some simple use cases

In this section, I'll show you some simple use cases for using the Web Storage API, specifically localStorage.

A game hiscore

If you're building a game that generates a score, then saving the user's hiscore is surely a must! localStoragewill coerce that score into a string but there are few ways to convert it back to a number:

localStorage.setItem('hiscore', 1984)
let hiscore = localStorage.getItem('hiscore')
console.log(typeof hiscore) // logs: 'string'

let hiscoreMultiply = hiscore * 1
console.log(typeof hiscoreMultiply) // logs: 'number'

Another way to convert hiscore is to use the Number() object:

let hiscoreNumber = Number(hiscore)
console.log(typeof hiscoreNumber) // logs: 'number'

Lastly, you can use JSON.parse():

let hiscoreParse = JSON.parse(hiscore)
console.log(typeof hiscoreParse) // logs: 'number'

To-do list data

For coding a to-do list app, your list of items will likely be stored as objects inside an array. To put this array into storage, it needs to be converted to a string first, which you can do using JSON.stringify():

let todolist = [
  {id: 1, item: 'make fresh coffee', checked: true}, 
  {id: 2, item: 'learn to code', checked: false},
  {id: 3, item: 'feed Takeshi', checked: false}
  ]

let storeMe = JSON.stringify(todolist)
localStorage.setItem('todolist', storeMe)

When retrieving the to-do list, you'll want to convert the string back into an object:

let unStoreMe = JSON.parse(localStorage.getItem('todolist'))

Light/dark mode preference

If you're designing a webpage with a light/dark mode toggle, then it's a good idea to store the user's preference for future visits. Typically, this will mean dealing with a boolean that gets coerced into a string when put in localStorage.

Again, JSON.parse() comes to the rescue:

let isDarkThemeOn = true
localStorage.setItem('isDarkThemeOn', isDarkThemeOn)
console.log(typeof localStorage.getItem('isDarkThemeOn')) // logs: 'string'

isDarkThemeOn = JSON.parse(localStorage.getItem('isDarkThemeOn'))
console.log(typeof isDarkThemeOn) // logs: 'boolean'

Conclusion

Using the localStorage object, you can quickly and easily store and retrieve data from the user's browser. This data will have no expiration data and can only be manipulated through JavaScript or the dev tools. However, it can be deleted if the user clears their browser cache.

When you add primitive data types to the localStorage object, they will automatically be converted to strings. For arrays and objects, you will need to stringfy them before saving to localStorage. You can convert the strings back to their original data type using JSON.parse().

Sources

ย