HTML5 Local Storage fallback solutions

JavascriptJqueryFlashHtmlLocal Storage

Javascript Problem Overview


I'm looking for javascript libraries and code that can simulate localStorage on browsers that do not have native support.

Basically, I'd like to code my site using localStorage to store data and know that it will still work on browsers that don't natively support it. This would mean a library would detect if window.localStorage exists and use it if it does. If it doesn't exist, then it would create some sort of fallback method of local storage, by creating its own implementation in the window.localStorage namespace.

So far, I've found these solutions:

  1. Simple sessionStorage implementation.
  2. An implementation that uses cookies (not thrilled with this idea).
  3. Dojo's dojox.storage, but it is it's own thing, not really a fallback.

I understand that Flash and Silverlight can be used for local storage as well, but haven't found anything on using them as a fallback for standard HTML5 localStorage. Perhaps Google Gears has this capability too?

Please share any related libraries, resources, or code snippets that you've found! I'd be especially interested in pure javascript or jquery-based solutions, but am guessing that is unlikely.

Javascript Solutions


Solution 1 - Javascript

Pure JS based simple localStorage polyfill:

Demo: http://jsfiddle.net/aamir/S4X35/

HTML:

<a href='#' onclick="store.set('foo','bar')">set key: foo, with value: bar</a><br/>
<a href='#' onclick="alert(store.get('foo'))">get key: foo</a><br/>
<a href='#' onclick="store.del('foo')">delete key: foo</a>​

JS:

window.store = {
    localStoreSupport: function() {
        try {
            return 'localStorage' in window && window['localStorage'] !== null;
        } catch (e) {
            return false;
        }
    },
    set: function(name,value,days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime()+(days*24*60*60*1000));
            var expires = "; expires="+date.toGMTString();
        }
        else {
            var expires = "";
        }
        if( this.localStoreSupport() ) {
            localStorage.setItem(name, value);
        }
        else {
            document.cookie = name+"="+value+expires+"; path=/";
        }
    },
    get: function(name) {
        if( this.localStoreSupport() ) {
            var ret = localStorage.getItem(name);
            //console.log(typeof ret);
            switch (ret) {
              case 'true': 
                  return true;
              case 'false':
                  return false;
              default:
                  return ret;
            }
        }
        else {
            // cookie fallback
            /*
             * after adding a cookie like
             * >> document.cookie = "bar=test; expires=Thu, 14 Jun 2018 13:05:38 GMT; path=/"
             * the value of document.cookie may look like
             * >> "foo=value; bar=test"
             */
            var nameEQ = name + "=";  // what we are looking for
            var ca = document.cookie.split(';');  // split into separate cookies
            for(var i=0;i < ca.length;i++) {
                var c = ca[i];  // the current cookie
                while (c.charAt(0)==' ') c = c.substring(1,c.length);  // remove leading spaces
                if (c.indexOf(nameEQ) == 0) {  // if it is the searched cookie
                    var ret = c.substring(nameEQ.length,c.length);
                    // making "true" and "false" a boolean again.
                    switch (ret) {
                      case 'true':
                          return true;
                      case 'false':
                          return false;
                      default:
                          return ret;
                    }
                }
            }
            return null; // no cookie found
        }
    },
    del: function(name) {
        if( this.localStoreSupport() ) {
            localStorage.removeItem(name);
        }
        else {
            this.set(name,"",-1);
        }
    }
}​

Solution 2 - Javascript

I use PersistJS (github repository), which handles client-side storage seamlessly and transparently to your code. You use a single API and get support for the following backends:

  • flash: Flash 8 persistent storage.
  • gears: Google Gears-based persistent storage.
  • localstorage: HTML5 draft storage.
  • whatwg_db: HTML5 draft database storage.
  • globalstorage: HTML5 draft storage (old spec).
  • ie: Internet Explorer userdata behaviors.
  • cookie: Cookie-based persistent storage.

Any of those can be disabled—if, for example, you don't want to use cookies. With this library, you'll get native client-side storage support in IE 5.5+, Firefox 2.0+, Safari 3.1+, and Chrome; and plugin-assisted support if the browser has Flash or Gears. If you enable cookies, it will work in everything (but will be limited to 4 kB).

Solution 3 - Javascript

have you seen the polyfill page on the Modernizr wiki?

https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills

look for the webstorage section on that page and you will see 10 potential solutions (as of July 2011).

good luck! Mark

Solution 4 - Javascript

Below is a tidied up version of Aamir Afridi's response that keeps all its code encapsulated within the local scope.

I've removed references that create a global ret variable and also removed the parsing of stored "true" and "false" strings into boolean values within the BrowserStorage.get() method, which could cause issues if one is trying to in fact store the strings "true" or "false".

Since the local storage API only supports string values, one could still store/retrieve JavaScript variable data along with their appropriate data types by encoding said data into a JSON string, which can then be decoded using a JSON encode/decode library such as https://github.com/douglascrockford/JSON-js

var BrowserStorage = (function() {
	/**
	 * Whether the current browser supports local storage as a way of storing data
	 * @var {Boolean}
	 */
	var _hasLocalStorageSupport = (function() {
		try {
			return 'localStorage' in window && window['localStorage'] !== null;
		} catch (e) {
			return false;
		}
	})();
	
	/**
	 * @param {String} name The name of the property to read from this document's cookies
	 * @return {?String} The specified cookie property's value (or null if it has not been set)
	 */
	var _readCookie = function(name) {
	    var nameEQ = name + "=";
	    var ca = document.cookie.split(';');
	    for (var i = 0; i < ca.length; i++) {
	        var c = ca[i];
	        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
	        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
	    }
	    
	    return null;
	};
	
	/**
	 * @param {String} name The name of the property to set by writing to a cookie
	 * @param {String} value The value to use when setting the specified property
	 * @param {int} [days] The number of days until the storage of this item expires
	 */
	var _writeCookie = function(name, value, days) {
		var expiration = (function() {
			if (days) {
				var date = new Date();
				date.setTime(date.getTime() + (days*24*60*60*1000));
				return "; expires=" + date.toGMTString();
			}
			else {
				return "";
			}
		})();
		
		document.cookie = name + "=" + value + expiration + "; path=/";
	};
	
	return {
		/**
		 * @param {String} name The name of the property to set
		 * @param {String} value The value to use when setting the specified property
		 * @param {int} [days] The number of days until the storage of this item expires (if storage of the provided item must fallback to using cookies)
		 */
		set: function(name, value, days) {
			_hasLocalStorageSupport
				? localStorage.setItem(name, value)
				: _writeCookie(name, value, days);
		},
		
		/**
		 * @param {String} name The name of the value to retrieve
		 * @return {?String} The value of the 
		 */
		get: function(name) {
			return _hasLocalStorageSupport
				? localStorage.getItem(name) 
				: _readCookie(name);
		},
		
		/**
		 * @param {String} name The name of the value to delete/remove from storage
		 */
		remove: function(name) {
			_hasLocalStorageSupport
				? localStorage.removeItem(name)
				: this.set(name, "", -1);
		}
	};
})();

Solution 5 - Javascript

I personally prefer amplify.js. It has worked really well for me in the past and I recommended it for all local storage needs.

> supports IE 5+, Firefox 2+, Safari 4+, Chrome, Opera 10.5+, iPhone 2+, Android 2+ and provides a consistent API to handle storage cross-browser

Solution 6 - Javascript

store.js uses userData and IE and localStorage on other browsers.

  • It does not try to do anything too complex

  • No cookies, no flash, no jQuery needed.

  • Clean API.

  • 5 kb compressed

https://github.com/marcuswestin/store.js

Solution 7 - Javascript

The MDN page for DOM storage gives several workarounds that use cookies.

Solution 8 - Javascript

Lawnchair seems to be a good alternative too

> a lawnchair is sorta like a couch except smaller and outside. perfect > for html5 mobile apps that need a lightweight, adaptive, simple and > elegant persistence solution. > > - collections. a lawnchair instance is really just an array of objects. > - adaptive persistence. the underlying store is abstracted behind a consistent interface. > - pluggable collection behavior. sometimes we need collection helpers but not always.

Solution 9 - Javascript

There is realstorage, which uses Gears as a fallback.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTaurenView Question on Stackoverflow
Solution 1 - JavascriptAamir AfridiView Answer on Stackoverflow
Solution 2 - Javascriptjosh3736View Answer on Stackoverflow
Solution 3 - JavascriptMark LummusView Answer on Stackoverflow
Solution 4 - JavascriptStevenView Answer on Stackoverflow
Solution 5 - JavascriptraidfiveView Answer on Stackoverflow
Solution 6 - JavascriptMikko OhtamaaView Answer on Stackoverflow
Solution 7 - JavascriptalexView Answer on Stackoverflow
Solution 8 - Javascriptj0kView Answer on Stackoverflow
Solution 9 - JavascriptGauravView Answer on Stackoverflow