Channels ▼

Web Development

The localStorage API

Example: QuizCards

QuizCards is a Chrome extension that I wrote for learning a language through interactive flash cards. Once installed, the extension lives only in your browser, via an icon on the toolbar. As you answer the flash cards, the extension uses localStorage to remember which cards you answered correctly and how many times, so that it can be smart about which ones to show you next.

Here's an example of what it stores in localStorage:

german-answer-mode multiple-choice
german-ham-Schinken {"lastAsked":1322691448489, "timesAsked":1, "timesCorrect":1, "timesIncorrect":0}
german-bucket1 [{"id":"arm-Arm","lastAsked":0}, {"id":"cheek-Backe","lastAsked":0}, {"id":"belly-Bauch","lastAsked":0},…

Retaining Application State

Even if you are using a server to store user preferences and data, there are still some types of data that are better to store on the client, because they are actually about the client — like the current "state" of the website.  Some websites are more like static documents, and don't really have a state beyond where the users have scrolled to, but other websites (such as gmail) are more like applications, with many different sections that can be opened, closed, and moved around, all under the same URL. Users doesn't always expect application state to follow them across clients, and it can be overkill to store the data on your server. If you realize that you do need to store the data there, you can always migrate it later.

Example: EatDifferent

EatDifferent is the website I'm working on now, and it's more of an app than a document. It's a nutrition tracking tool for users to log their updates and view others updates, and features the stream of latest updates on the home screen. I use localStorage to remember which stream filter the user most recently clicked, and also to remember which UI messages the user has seen and dismissed.

Here's an example of what it stores in localStorage:

cache-promo-supplies-jan30 hidden
lscache-stream-filter-users everyone

Example: jshint

JSHint is a tool for checking the quality of JavaScript code, and since JavaScript style is so variable, it includes many options for evaluating the quality. The JSHint website features an interactive tool that lets you paste in code and report problems with it, and it uses localStorage to remember your enabled options for the next time you visit.

It stores all the options as a serialized object in one key:

opts {"debug":true, "forin":true, "eqnull":false, "noarg":true, "noempty":false, "eqeqeq":true, "boss":false, "loopfunc":true, "evil":true, "laxbreak":true, "bitwise":true, "strict":true, "undef":true, "curly":true, "nonew":true, "browser":true, "devel":false, "jquery":false, "es5":false, "node":false}

Remembering Form Input

You can also use localStorage to remember user-entered form input, like their login username, commonly filled options in forms (like location and phone number), and long text input that they may accidentally forget to save. It's a great use of localStorage because form input doesn't need to be remembered — but when it is, it can bring a lot of joy to the user — almost like magic. But if for some reason localStorage isn't supported or the user changes computers, they won't actively notice their form input hasn't followed them. If you decide to use localStorage to remember form input, don't just remember everything — carefully consider which parts of a form should be remembered, and for how long. There are a few libraries specially designed for remembering forms, notably autoStorage and savify.

The website lets developers create tests to compare performance of JavaScript snippets, and it starts with a form for creating new test cases. The website uses localStorage to remember author information, since that's the same across tests, and then it uses that same author information to auto-populate the commenting form.

It stores the author information in 3 keys in localStorage:

author-email [email protected]
author Pamela Fox

Example: Disqus

Disqus is a popular embedded commenting system for blogs and websites [and used on Dr. Dobb's –Ed.]. It  adds a feature that uses localStorage to remember any text a user typed in a comment box but didn't post — so that when users leave a Web page and return, they'll see their draft still there, waiting to be posted. The Twitter web client also does this, and they also save an expiration for the draft, so that they don't show it after a certain point.

Disqus stores the drafts in one localStorage key, and keys it by thread name and website:

disqus.drafts [{"thread:delayed_image_loading_on_long_pages": "I'm going to write a really long and epic comment, and I will be really mad if I accidentally move away from the page and lose this comment, mmm kay?"}]

Improving performance

Websites are increasingly reliant on AJAX and API requests, and in many cases, the results of these requests can be cached so that users do not have to wait as long. The traditional way of caching server-side requests is to set cache headers on the server so the browser serves them out of its own cache, but there are times when it's better to use localStorage. First, you have more control when you can do the caching yourself — you can decide when to invalidate resources and cache requests for different amounts of time in different areas on your site. You can also decide to first load from your cache and then refresh the cache, improving the apparent loading speed for a page. If you're developing for mobile browsers, you can significantly improve your performance there by using localStorage instead of relying on their browser cache, because many mobile browsers have smaller caches and can do less HTTP requests than desktop browsers.

There are several libraries customized for caching – such as lscache, which we discussed earlier (and an lscache jQuery plugin), YQL localCache for caching YQL API results, jQuery offline for storing AJAX results, and Inject and basket.js for caching JS files.

Example: RageTube

RageTube is a website that I made for watching music videos based on online playlists. It uses a server-side XMLHR to scrape and parse the HTML playlists, and it uses the YouTube API to find the top result for each song on YouTube. I use localStorage (via my lscache library) to store the results of the playlist scraping indefinitely, and to store the API results for a few days (because video searches don't change often). When a user watches the same playlist often, the app won't have to make so many XMLHRs and API requests, making it both faster for the user and cheaper for me, the developer.

For each request, there are two keys in localStorage, one to store the actual data, and one to remember the expiration date:

YouTube: Hot Chip I Feel Better [{"id":"5GOZjlwIwfk","uploaded":"2010-03-17T17:53:17.000Z","category":"Music","title":"Hot Chip — I Feel Better",…
YouTube: Hot Chip I Feel Better-expiration

parser: http://www.a… {"songs":[{"artist":"Angus & Julia Stone","title":"Big Jet Plane","id":"angusandamp; julia stone-big jet plane"},…

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.