Storing Data the Simple HTML5 Way (and a few tricks you might not have known)

Yes indeed people, it’s your favourite HTML5 Doctor with JavaScript knowledge who lives in Brighton near a golf course! I’m also shooting for the longest title we’ve published so far – and I think I’m in the lead.

This post is about the Web Storage API. Technically it’s been shifted out of the HTML5 specification and can now be found in it’s very own dedicated spec. But if it counts at all – it used to be part of the Web Applications spec.

Web Storage is a very, very simple way to store data in the client – i.e. the browser. What’s more, the support is fabulous: IE8 and upwards has support natively, and there’s lots of good polyfills in the wild already.

This post however will just focus on the features of Web Storage and hopefully show you a trick or two you may not have known about.

What Web Storage Does

Using JavaScript, Web Storage makes it possible to easily store arbitrary values in the browser. Storage is different from cookies in that it’s not shared with the server. It’s also different from cookies in that it’s dead simple to work with.

There are two versions of Web Storage: local and session. Local means that it’s persistent, and session is simply that the data is lost when the session ends (i.e. when you close you browser window or tab). It’s also worth noting that a session is tied to a single browser window or tab. The session doesn’t leak out in to other open windows on that same domain.

Any data stored is tied to the document origin, in that it’s tied to the specific protocol (http or https, etc), the host (html5doctor.com) and the port (usually port 80).

Get Storing

The API for localStorage and sessionStorage is exactly the same, and distills down to the following methods:

.setItem(key, value);

.getItem(key)

.removeItem(key)

.clear()

.key(index)

.length

You can probably guess what most of those methods do, maybe not the last two, but ignore all that syntax for a moment.

Due to the way that the storage API has been defined, the set/get/remove methods all are getters, setters and deleters. What that means to you is you can use localStorage as follows:

What’s happening under the hood is that when you set a property on localStorage (or sessionStorage) it’s calling the .setItem method. When you get a property, it’s calling .getItem and when you delete, it’s calling removeItem. That way you can treat the Web Storage interface as any other regular object in JavaScript, except you’ll know it’ll hang around after the page has unloaded.

Hey everyone! I’m storing some data!

That’s what your browser does when you store some data. It announces it via events.

When you set some data on localStorage or sessionStorage, an event, called “storage”, fires on all the other windows on the same origin.

Note that as IE8 has support, if you don’t want to use onstorage you’ll want to double up your event listeners with attachEvent.

Clearly a massive alert box isn’t useful, but what is useful is what you capture inside of the event object:

key – the property name of the value stored

newValue – the newly set value (duh!)

oldValue – the previous value before being overwritten by .newValue

url – the full url path of the origin of the storage event

storageArea – the storage object, either localStorage or sessionStorage

With this information, you can do a lot with the storage event, like perhaps keep tabs that are open synchronised. Here’s a simple, contrived example of using localStorage to echo a value across different windows on html5demos.com.

Gotchas to watch out for

The main gotcha with Web Storage is that although the specification used to say† that any object type can be stored, in fact all browsers currently coerce to strings. That means if you want to store a JavaScript object (or an array perhaps), you’ll need to use JSON to encode and decode:

When working with storage events, a couple of things to also watch out for – this is on purpose of course, but still just about qualify for gotcha status:

The event only fires on the other windows – it won’t fire on the window that did the storing.

The event won’t fire if the data doesn’t change, i.e. if you store .name = ‘Remy’ and set it to ‘Remy’ again it won’t fire the storage event (obviously, since nothing was stored).

and finally…

If you want to use web storage in browsers like IE6 and IE7 (or rather than want: need to in your particular case) – then there’s no shortage of polyfills for Web Storage. However be wary that you’ll need to stick to the regular setItem syntax rather than being able to use the sexy setter/getter syntax – and I’ve yet to see a polyfill that supports the storage events.

Maybe that isn’t a problem for you though – maybe the sheer simplicity and spiffingness of Web Storage is enough to just support IE8 and above with this enhanced client storage model.

30 Responses on the article “Storing Data the Simple HTML5 Way (and a few tricks you might not have known)”

> The main gotcha with Web Storage is that although the specification says that any object type can be stored,

The spec changed.

Also, maybe you should mention that Web storage suffers from being racy if the browser uses different processes for different tabs. Which is the reason some browser developers don’t want anyone to ever use Web Storage. (Cookies suffer from this problem as well, though.)

By “racy”, he’s referring to race conditions, where different things can occur based on the order that supposedly-independent things ran in.

For example, say you were storing a counter in localStorage, and wanted to increment it. You might do something simple like this:

localStorage.foo = localStorage.foo+1;

In between the time you retrieved the value and stored the modified value, another tab running in a different process might have stored a *different value* there, which you would overwrite. That means lost increments on your counter!

Of course, the time window in this example is miniscule, but more realistic examples are easy to imagine where you pull out a bit of data, do some expensive computation that takes a couple cycles, then store it back. There’s a greater possibility for problems there.

Of course, the exact same problem exists with cookies, which doesn’t seem to have bothered people much, so this probably isn’t a big deal in practice. Every once in a while you might have data corruption, is all.

Other techs like IndexedDB solve this problem by implementing proper transactions and write-locks and such, but they’re not nearly as simple as localStorage.

It strikes me that this is the perfect solution to that “God damn it! I just lost everything I was typing into a textarea!” problem. It would be a nice enhancement for the browsers that support Web Storage (storing the contents of the textarea periodically) and for browsers that don’t …well, that’s the current situation for typing things into textareas on the web anyway.

@Neils – for degrading, get yourself a polyfill – web storage polyfills are pretty well established now and work just fine in old browsers like Netscape 1 point who uses this (link at the start of the article).

As for disallowing – you can prevent cookies, but I’ve personally not found a way to prevent localStorage (I’m sure there is, but browsers bury it pretty deep nowadays). That said, if you’re supporting Firefox 3.6, and the user has disabled cookies, web storage won’t work either – I can’t say the whether the functionality is the same in FF6 or not. If that’s the case, you need to detect for cookies and proceed from there. That’s what I do in JS Bin: https://github.com/remy/jsbin/blob/master/js/chrome/storage.js – note that sessionStorage, the variable in JS Bin’s code is locally scoped and not the native implementation until around line 23.

@Jeremy, Disqus actually already saves your draft comments in localStorage, which I agree is super handy. I know Chrome will restore all form field data it can (i think only if those elements are in the original markup).

But yeah localStorage works great for forms; some sites cache your email/username and populate the login form with it each time to save you a few keystrokes.

nice article, didn’t know the storage event. It might even be used to allow communication between otherwise unlinked browser windows / tabs. So instead of using a SharedWorker (Chrome only, atm.) to broker events, you could work something out with these events. nice.

Regarding your »…and I’ve yet to see a polyfill that supports the storage events.« have a look at http://medialize.github.com/jQuery-browserEvent/ (gloryfied proof of concept) – where I tried to enable cross window communication down to IE6. One might take this approach to enable the events. A bit chicken/eggy, though.

Additionally, as stated in the chromium issue above’s comments, localStorage performance degrades as size increases and is considered slower than IndexedDB, though with the benefit of a FAR SIMPLER API and broader browser support (IE8, FF3.5, S4, Chr4, O10.5).

Not knowing available size is a gotcha. For example, Jeremy Keith suggests using localStorage as a backup for textArea content. If storing all the content generates a QUOTA_EXCEEDED_ERR exception, then I’d prefer to store as much content as possible. But since there’s no API to determine what’s available I have to use trial and error with various sizes.

During testing, I found some behaviour is not consistent accross browsers when using sessionStorage and opening a link in a new tab.

- Chrome and Firefox copy sessionStorage content in the new page, but don’t share it
- Safari doesn’t copy it at all
- Opera copies and shares (ie if you modify it in one page, it will reflect in the other).

(note: this is the behaviour at the end of 2010, I didn’t test since then).

As I understand the specification, the good behaviour is the one from Chrome and Firefox.

Other gotchas :
- localStorage is shared using the “origin”, ie scheme + host + port. It means any page on the same origin will have access to the same localStorage
- on the other hand, if your website/application use different subdomains and/or scheme (think http and https), then you won’t have access to the same data.

Very nice article and I haven’t implemented this yet so I may be wrong by asking the following question but how secure is Local Storage? If by chance I save lets say an unencrypted username in local storage by using something like.

localStorage.username = 'bizzy';

Lets say I run that code on my own website and then the visitor goes to another website and they use the same localStorage.username value to try and retrieve username, is the other website able to retrieve it?

As you said you need to supply a URL so there is no cross-connection behaviour like this but maybe the other website owner is clever and uses the referrer URL and maybe that URL was the one that stored the data.

Basically could I access a stored value on my website using a URL and value that was stored on another website?

I know you could just as easily encrypt all your data before putting it in localStorage to avoid any possible malicious activity from another webmaster but I like to think about all these little possible security quirks from time to time.

I’ve found out that when you checking property which is undefined key in storage,
you get different result between by-using “.getItem()” and by-accessing getter.
Also, some browser returns different results from other.

—-
e.g.
(expecting value sessionStorage.undefined_session_property has never been set in previous activity.)

Can’t figure out why this is not working? please could someone share some knowledge and help me out. Thanks.

Trying to store info locally using php to dynamically create new storage variables per input. I can get it to work with the first div that was dynamically created using php but it will not work for the other divs that were created.

Hello Remy,
I am a Newbie to web storage…could you please help me to figure out what kind of data or item that we can store locally……….like if i have same pictures,videos and audios……..then how can i store them locally.

I’m new to JS and I’m trying hard to wrap my head around JSON and localStorage. I have an form that allows for 21 distinct text inputs. I’m trying to pass the 21 inputs to a second web page that will process and manipulate the data. Thanks to this article, I’m starting to understand that localStorage is a single container like a bucket to store data. I mistakenly thought that I could create 21 different localStorage containers for my form data. It seems to not work that way at all.

At least now, I get that I have to store all 21 entries into one bucket in the first html page and then pull them out from that bucket in the second html page.