Building Web Pages with Local Storage

Storage – when you’re building or renovating a house, storage is something you need. The more the better. This same principle applies to building websites; you need to store data somewhere.

Traditionally this has either been stored on the server using sessions or cache, but moving forward, there’s Web Storage, AKA Local Storage or Session Storage. Web Storage in HTML5 allows you to store information in the users browser. As far as I’m concerned, this is a game changer. Moving storage from the server improves performance by alleviating the need to transfer data between the server and the client. This article will focus on local storage, not session storage.

Web Storage is similar to HTTP cookies. Data is stored in the browser even if the user closes the browser, navigates away from your website, or restarts their browser. The biggest difference though is Web Storage isn’t transferred to the server on each request. Another difference is web storage doesn’t expire, unless you explicitly tell it to.

What’s The Difference Between Session and Local Storage?

The difference between session and local storage is local storage persists even if the browser is closed. Session storage data is not persisted beyond a session, so if you close the window or tab, the data disappears. But, while you’re shopping, the data in one window will be kept completely separate from that in another window if the site leverages the session storage data store.

Who Supports What?

Currently the major browsers support web storage natively. Here they are:

  • IE8+
  • FireFox 3.6+
  • Opera 10.5+
  • Chrome 5+
  • Safari 4+
  • iOS 3.2+
  • Android 2.1+

This is always changing, so a good place to keep up to date on which browsers support what, you can check out quirksmode.

Where’s the Data Stored?

Wouldn’t the web be a wonderful place if everything was the same? Web storage is stored at different locations on disk depending on which browser you’re using. I couldn’t find the exact locations for all of the browsers, so if you read this and you do know, please write a comment letting us know where it’s stored.

IE8+%userprofiles%/Local Settings/Application Data/Microsoft/Internet Explorer/DOMStore. There’s an XML file which contains the data

Firefox – data is stored in the webappsstore.sqlite file in the profile folder. There are some Firefox addons you can download to view the contents.

Chrome
Windows XP – C:Documents and Settings%username%Local SettingsApplication DataGoogleChromeUser DataDefault
Vista/7 – C:Users%username%AppDataLocalGoogleChromeUser DataDefault
Safari – data is stored in the sqllite file in C:Users%username%AppDataLocalApple ComputerSafariLocalStorage. There’s a localstorage file named the same as the website storing it.

Web Storage and JavaScript

Each domain and subdomain has unique web storage. Web storage is limited to a domain, so if any members of the web storage object are accessed by scripts whose origin is not the same origin of the Document object, a SecurityError is thrown.

Access to web storage is via the localStorage object. This returns a Storage interface. This interface has a number of functions available to manipulate the web storage. Data in the web storage is stored in key/value pairs, so you can store strings, but most likely you’ll want to store a JSON object. Unlike the sessionStorage interface, localStorage persists data when the user closes the browser, or when they open multiple tabs or windows.

Before working with localStorage, you need to check if the browser supports it. You can write this manually, but a better way is to use the Modernizr JavaScript library. Modernizer checks browser features for you so you can concentrate on getting on with your work. Modernizr can be downloaded from here.

Starting at the beginning, check to see if localStorage is available.

if (Modernizr.localstorage) {    
    $("#result").text('localStorage is available');
} else {    
    $("#result").text('localStorage is not available');   
}

The sample code can be found here.

To add data, you can use the setItem function, add a new value via array syntax, or create a new property.  The following sample adds data in the three ways.


if (Modernizr.localstorage) {    
    var localStore = window.localStorage;
    localStore.setItem["Country"] = "USA";
    localStore["Country"] = "USA";
    localStore.Country = "USA";   
    $("#result").text(localStore.Country);
} else {    
    $("#result").text('localStorage is not available');   
}

The sample code can be found here.

If the size of the data is too big, an Out of memory error will be thrown. To avoid this error, a good idea is to check what space is available via the remainingSpace function. This return an integer value that has the remaining disk or memory quota.


if (Modernizr.localstorage) {
    var localStore = window.localStorage;
    if (localStore.remainingSpace > 0) {
        // you have space to do work
    }
} else {
    $("#result").text('localStorage is not available');
}

The sample code can be found here.

Update

I forgot to mention this, so here’s an update. The remaingSpace function is available in IE. The IE
team have put this method forward to the W3C, but so far it hasn’t made it into the specification.
A better way to check to see if you can add a piece of data is to add a try/catch around the piece of
code that sets the storage. As expected, each browser throws a different error. Here’s the code I
used to fill the local storage.


if (Modernizr.localstorage) {
var localStore = window.localStorage;
localStore.RandomData = "Random";

for (i = 0; i < 100; i++) {
var data = localStore.RandomData;

try {
localStore.RandomData = data + data;
} catch (e) {
$("#errorMessage").text(e.name + ' - ' + e.message + ' - ' + i);
break;
}

}
localStorage.removeItem("DATA");
} else {
$("#result").text('localStorage is not available');
}

And here’s the results error name followed by the error message for each browser.

Firefox 7.0.1

NS_ERROR_DOM_QUOTA_REACHED – Persistent storage maximum size reached

IE9

Error – Out of memory

Safari 5.1.1

QUOTA_EXCEEDED_ERR – QUOTA_EXCEEDED_ERR: DOM Exception

Chrome 15.0.874

QUOTA_EXCEEDED_ERR – QUOTA_EXCEEDED_ERR: DOM Exception

The sample code can be found here. On a side note, IE9 would stop responding for me on this page,
so the only way to test this was to create a separate page on my personal website. It’s the same
code and you can visit it here.

Removing data from localStorage is easy too.  Calling removeItem removes an item from the storage.

if (Modernizr.localstorage) {
    var localStore = window.localStorage;
    localStore.Country = 'USA';

    if (localStore.Country) {
        localStore.removeItem("Country");
    }
} else {
    $("#result").text('localStorage is not available');
}

The sample code can be found here.

Reading data from storage can be done via array syntax, or by the property.

if (Modernizr.localstorage) {
    var localStore = window.localStorage;
    localStore.Country = "USA";

    if (localStore.Country) {
        $("#result").text(localStore.Country);
    }
} else {
    $("#result").text('localStorage is not available');
}

The sample code can be found here.

Putting It All Together

Web storage is great, if the browser supports it. For older browsers, they won’t support web storage, but they will support cookies. A good fallback is to store the data inside a cookie if web storage isn’t available. The following example does just that.

$(function() {
    $("#write").bind("click", function() {
        if (Modernizr.localstorage) {
            // your browser supports localStorage
            var localStore = window.localStorage;
            localStore.Country = "USA";
        } else {
            // your browser doesn't supports localStorage
            // write to a cookie
            var exdate = new Date();
            exdate.setDate(exdate.getDate() + 365);
            var cookie = "USA" + "; expires=" + exdate.toUTCString();
            document.cookie = "Country=" + cookie;
        }
    });
    $("#read").bind("click", function() {
        $("#result").text("");
        if (Modernizr.localstorage) {
            // your browser supports localStorage
            var localStore = window.localStorage;
            $("#result").text(localStore.Country);
        } else {
            // your browser doesn't supports localStorage
            // write to a cookie
            var cookies = document.cookie.split(";");
            for (i = 0; i < cookies.length; i++) {
                x = cookies[i].substr(0, cookies[i].indexOf("="));
                y = cookies[i].substr(cookies[i].indexOf("=") + 1);
                x = x.replace(/^s+|s+$/g, "");
                if (x === "Country") {
                    $("#result").text(unescape(y));
                }
            }
        }
    });
    $("#remove").bind("click", function() {
        if (Modernizr.localstorage) {
            // your browser supports localStorage
            var localStore = window.localStorage;
            localStore.removeItem("Country");
        } else {
            // your browser doesn't supports localStorage
            // so remove the cookie
            var cookies = document.cookie.split(";");
            for (i = 0; i < cookies.length; i++) {
                x = cookies[i].substr(0, cookies[i].indexOf("="));
                y = cookies[i].substr(cookies[i].indexOf("=") + 1);
                x = x.replace(/^s+|s+$/g, "");
                if (x === "Country") {
                    var cookie = 'USA; expires=Thu, 01-Jan-70 00:00:01 GMT;';
                    document.cookie = "Country=" + cookie;
                }
            }
        }
    });
});

The sample code can be found here.

Web storage is a great addition to your armor when you need to build a great website. Storing data on the client reduces the amount of memory that’s needed on the server, and it also brings the data closer to the user, which means better performance. How much better, well that all depends on how much data you’re storing. But the common sense rule applies; don’t stick huge amounts of data in web storage.  Keep things as lightweight as possible. Your users will thank you in the end.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • MStalfoort

    Hey Malcolm

    Interesting article. I was wondering since you’re referring to a “remainingSpace” function on where I could find that one. It isn’t part of Modernizr and also not part of the spec so I’m very curious and if you could point me to the source of that function that would be great.

  • Peter

    Hi,

    You have a small error in your second code snippet: “localStore.setItem["Country"] = “USA”;” should be written as “localStore.setItem(“Country”,”USA”)”. “setItem” is a method with the two arguments: “key” and “value”. For further info: http://dev.w3.org/html5/webstorage/.

    Peter

  • http://onespirit.wetpaint.com/ AnilG

    Is access restricted to *sub-domains* or just domains? Can x.y.com also access y.com data or can y.com access x.y.com data?

    What are the security implications? Presumably any XSS attack (injected into the domain) can harvest all the data available in the domain’s app store automatically and return it to the attacker?

    When you say stored as a JSON object do you mean a JSON representation of an object stored as a string requiring the string to be parsed every time you want the data in the object thus forcing the web app to build an additional layer on top of the storage to generate and cache app store data on a lazy basis to ensure performance for comprehensive data store usage?

    Or does the suggestion to use cookies as a fall back imply that the extent of storage that this feature is appropriate for is highly limited, to the scale that cookie storage is limited to? Suppose your web app needs to store multi-level hierarchical data with dozens of objects at the top level and hundreds or thousands of multi-field objects at lower levels. Is this kind of usage completely inappropriate for web storage?

    If so the game is still little league. I got really excited when I heard about HTML 5 persistent storage but for the scope and scale I want for my web apps it is highly disappointing and basically unusable.

    I don’t understand, in this era where web browsers are basically the thin clients for potentially all domestic, business and enterprise operations, why standards design is not making them seriously thicker.

  • Malcolm Sheridan

    @MStalfoort

    Yes that was an oversight by me. The remainingSpace function is available in IE only. The IE team have said this should be part of the specification, and they are right. Since you posted this comment I’ve updated the article to include this.

    @Peter

    Thanks for the correction.

  • http://www.bahrul-ulum.com/ Belajar Template

    Thanks Malcolm, You give me a knowledge ofr bulid a better website,especially for caching a web

  • http://games.webblocks.nl Rudie

    Another nice source of support & compatibility: http://caniuse.com/

    > Each domain and subdomain has unique web storage.

    It’s actually unique for scheme + domain + port. Yes, HTTP and HTTPS have a different storage. (As far as I know `www.example.com` has a different storage than `example.com`.)