All posts by realboxed

Way to Offline Apps

Offline-First Awesome

Useful resources for creating Offline-First web apps

“Web” and “online” are two closely associated terms, downright synonymous to many people. So why on earth would we talk about “offline” web technologies, and what does the term even mean?


Inspired by the awesome list thing.

Table of Contents

W3C Specification

Offline Web Applications

This specification highlights features (SQL, offline application caching APIs as well as online/offline events, status, and the localStorage API) from HTML5 and provides brief tutorials on how these features might be used to create Web applications that work offline.

Service Workers

This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.


This specification defines APIs for a database of records holding simple values and hierarchical objects. Each record consists of a key and some value. Moreover, the database maintains indexes over records it stores. An application developer directly uses an API to locate records either by their key or by using an index. A query language can be layered on this API. An indexed database can be implemented using a persistent B-tree data structure.


This specification defines an API for persistent data storage of key-value pair data in Web clients.


The Offline First Reader. A monthly reader featuring all things Offline First, covering theory, technology and user experience for new offline use cases.


Service Worker notes (Jeremy Keith – Feb 4, 2016)

Making A Service Worker: A Case Study (Lyza Danger Gardner – Feb 1, 2016)

Create a really, really simple offline page using Service Workers (Dean Hume – Jan 25, 2016)

Offline Web Applications: Using IndexedDB & Service Worker (Michael Wales – Jan 20, 2016)

Building Offline Sites with ServiceWorkers and UpUp (Tal Ater – Jan 19, 2016)

Instant Web Application (Gleb Bahmutov – Dec 24, 2015)

Introducing Background Sync (Jake Archibald – 2015)

Beyond Offline (Salvador de la Puente González – Dec 21, 2015)

Getting started with the Service Worker Toolbox (Dean Hume – Dec 17, 2015)

ServiceWorker Cookbook (by Mozilla)

Offline Web Applications with CouchDB, PouchDB and Ember CLI (Chris Moore – Dec 10, 2015)

A Hoodie Case Study: How does offline (Alex Feyerke – Dec 1, 2015)

Reducing Single Point of Failure using Service Workers (Dean Hume – Dec 1, 2015)

Building realtime collaborative offline-first apps with React, Redux, PouchDB and WebSockets (Pedro Teixeira – Nov 30, 2015)

Cache-limiting in Service Workers …again (Jeremy Keith – Nov 29, 2015)

Introducing a progressive webapp for Pokémon fans (Nolan Lawson – Nov 23, 2015)

Cache-limiting in Service Workers (Jeremy Keith – Nov 19, 2015)

Offline Recipes for Service Workers (David Walsh – Nov 19, 2015)

Instant Loading Web Apps With An Application Shell Architecture (Addy Osmani – Nov 17, 2015)

An Offline Experience with Service Workers (Brandon Rozek – Nov 14, 2015)

Building Flipkart Lite: A Progressive Web App (Aditya Punjani – Nov 11, 2015)

Your first offline web app (Chrome Developer Team – 2015)

Making a Simple Site Work Offline with ServiceWorker (Nicolas Bevacqua – Nov 10, 2015)

My first Service Worker (Jeremy Keith – Nov 7, 2015)

Building an offline page for (Oliver Joseph Ash – Nov 4, 2015)

Creating Offline-First Web Apps with Service Workers (Ryan Chenkie – Oct 30, 2015)

Cache sandboxed HTTP requests with Service Worker (Roman Liutikov – Oct 26, 2015)

ServiceWorker: Revolution of the Web Platform (Nicolas Bevacqua – Oct 21, 2015)

Taking the web offline with service workers (Ruadhan O’Donoghue – Oct 21, 2015)

Using Service Workers (MDN – Oct 18, 2015)

Don’t Wait for ServiceWorker: Adding Offline Support with One-Line (Kenneth Ormandy – Oct 14, 2015)

Service Workers in Production (Jeff Posnick – Oct 01, 2015)

How Do We Get It Done, Now? (Lyza Danger Gardner – Sep 30, 2015)

Why App Developers Should Think Offline-First (Chuck Ganapathi – Aug 30, 2015)

Let’s make Offline Web Applications secure! (Egor Homakov – Jul 28, 2015)

Service Worker Meeting Highlights (Ben Kelly – Jul 28, 2015)

Q&A: Offline first, not just mobile first says Couchbase (James Nunns – Jun 26, 2015)

Why offline-first matters, and what developers should know about it (Marcel Kalveram – Jun 2, 2015)

Getting Appcache’s Fallback to work, crossbrowser (Ian Devlin – Jun 1, 2015)

Mobile Apps Offline Support (Gustavo Machado – May 29, 2015)

Making work offline with Service Workers and free SSL from Cloudflare (Patrick Aljord – May 14, 2015)

Offline Data Synchronization in Ionic (Marco Fernandes – Apr 29, 2015)

Offline Data in the Browser (Assaf Weinberg – Mar, 2015)

Offline: When Your Apps Can’t Connect to the Internet (Daniel Sauble – Mar 29, 2015)

Offline is not just another mobile feature (Chuck Ganapathi – Mar 4, 2015)

Offline data in the browser (Assaf Weinberg – Mar, 2015)

Offline-first, fast, with the sw-precache module (Jeff Posnick – Feb 23, 2015)

Offline is Not a Feature (Feb 16, 2015)

The Right and Wrong Strategies When Taking Your App Offline (Martin Heller – Feb 9, 2015)

Three takeaways for web developers after two weeks of painfully slow internet (Gabor Lenard – Jan 25, 2015)

Offline first: as simple as unplug & play? (Thomas Anciaux – Jan 15, 2015)

A simple ServiceWorker app (Chris Haynes – Jan 6, 2015)

ServiceWorker is available in Chrome 40 beta (Ilya Grigorik – Dec 11, 2014)

PSA: Service Workers are Coming (Alex Russell – Dec 11, 2014)

The offline cookbook (Jake Archibald – Dec 9, 2014)

The next UX challenge on the web: gaining offline trust (Christian Heilmann – Dec 8, 2014)

Service Worker Recipes (Cesar William Alvarenga – Dec 8, 2014)

Introduction to Service Worker (Matt Gaunt – Dec 1, 2014)

offline decentralized single sign-on in the browser (James ‘substack’ Halliday – Nov 27, 2014)

Offline Web Apps with Meteor (Gabriel Poça, Nov 26, 2014)

How to build web applications that can work offline with PouchDB? (Yann Jacquot – Nov 25, 2014)

Making Your App Work Offline: Tips and Cautionary Tales (David Aragon – Nov 11, 2014)

How Google and Mozilla are aiming to make web apps shine offline (Nick Heath – Oct 30, 2014)

Offline-first is people-first (Nolan Lawson – Oct 3, 2014)

Introducing Hoodie: Full Stack App Development for Front-End Developers (Alvaro Oliveira – Sep 24, 2014)

Offline-first: a new paradigm in web development (Boye Oomens – Sep 16, 2014)

Building A Simple Cross-Browser Offline To-Do List With IndexedDB And WebSQL (Matt Andrews – Sep 2, 2014)

Introducing MakeDrive (David Humphrey – Aug 25, 2014)

Worklight Authentication done right with AngularJs (Gideon Simons – Aug 22, 2014)

Taking your Worklight apps offline (Gideon Simons – Aug 19, 2014)

Working offline (Aug 12, 2014)

Offline First – the new paradigm in web development done Neptune style (Njål Stabell – Augt 5, 2014)

Breaking Development: Offline First is the new Mobile First (Luke Wroblewski – Jul 29, 2014)

Offline Patterns (Carlos Andreu – Jul 3, 2014)

Offline Web Apps,Web Storage,IndexedDB,AppCache,File API Futures (Ali Alabbas – May 21, 2014)

Service Workers: Offline Now(ish)! (Alex Russell – May 21, 2014)

Offline Web Applications (Jan Jongboom – May 23, 2014)

Service Worker – first draft published (Jake Archibald – May 8, 2014)

The BMEAN Stack and Offline-First Design (Daishi Kato – Apr 11, 2014)

Do HTML5 apps have to be online all the time? (Christian Heilmann – Mar 23rd, 2014)

Building an Offline First App with PouchDB (Tiffany Brown – Mar 10, 2014)

Will It Work If I’m Offline? (Jacob Søndergaard – Mar 3, 2014)

Introduction to Offline Web Apps on the Kindle Fire (Russell Beattie – Jan 30, 2014)

Designing Offline-First Web Apps (Alex Feyerke – Dec 4, 2013)

Offline First: Learning from native experiences (Dion Almaer – Dec 4, 2013)

Offline First (Stuart Langridge – Nov 6, 2013)

Making the web work offline first (Marcel Kalveram – Nov 20, 2013)

Say Hello to Offline First (Dan Lash – Nov 5, 2013)

Offline First: Your Next Progressive Enhancement Technique? (Craig Buckler – Oct 30, 2013)

Appcache, not so much a douchebag as a complete pain in the #$%^ (John Allsopp – Jul 19, 2013)

Using HTML5 AppCache with Single Page Applications (Sergei Dorogin – Mar 29, 2013)

Offline First – A better HTML5 User Experience (Joe Lambert – Nov 26, 2012)

Application Cache is a Douchebag (Jake Archibald – May 08, 2012)

Appcache Facts

Chrome Offline Apps

Offline Support is Valuable, and You Can’t Add it Later (Aanand Prasad – Aug 13, 2011)

Offline-first web app design (Michiel B. de Jong – 2011)

5 Reasons Why There are no Killer Offline Web Applications (Craig Buckler – Feb 16, 2010

Offline Web Applications (Paul Rouget – Jan 7, 2010)

Let’s take this offline (Mark Pilgrim)



Offline-First Apps with PouchDB (Bradley Holt – Dec 11, 2015)

Worker as a Service (Ola Gasidlo – Nov 19, 2015)

Taking Your Web Apps Offline (Mike Nitchie – Nov 16, 2015)

There is a client-side proxy (ServiceWorker) in your browser! (Ilya Grigorik – Nov 16, 2015)

OnConnectionLost: The life of an offline web application (Stefanie Grewenig – Oct 12, 2015)

Offline First and Service Workers (Maximilian Stoiber – Oct 5, 2015)

Offline First Podcast (The Web Platform Podcast – Sep 8, 2015)

The Once & Future Web (Jake Archibald – Jul 28, 2015)

Go Offline (Rob Dodson – Jun 29, 2015)

Taking Ember Offline (John Kleinschmidt – Jun 16, 2015)

Holy sync (Eugenio Marletti – May 5, 2015)

Making Offline Suck Less with Service Workers (Bret Little – Mar 28, 2015)

Say Hello to Offline First (Ola Gasidlo – Mar 26, 2015)

The UX Of Offline-First (Jake Archibald – Mar 18, 2015)

The Web’s Future is Offline (John Allsopp – Feb 24, 2015)

Building Offline First Applications with Backbone (Gregor Martynus – Dec 17, 2014)

Working connected to create offline (Christian Heilmann – Nov 24, 2014)

The ServiceWorker is coming, look busy! (Jake Archibald – Sep 21, 2014)

The Next Challenge of the Web is Us (Christian Heilmann – Aug 1, 2014)

Offline First (Alex Feyerke – Jul 17, 2014)

The ServiceWorker: The network layer is yours to own (Jake Archibald – Jun 25, 2014)

Offline Web Applications (Jan Jongboom – May 23, 2014)

The Offline Web (Dale Harvey – Jun 20, 2014)

Bring NoSQL to your mobile (Patrick Heneise – Dec 16, 2013)

Network connectivity: optional (Jake Archibald – Dec 4, 2013)

Surviving the Offline Apocalypse (John Kleinschmidt – Nov 29, 2014)

Offline First (Jan Lehnardt – May 27, 2013)

Offline rules: Bleeding edge web standards at the Financial Times (Andrew Betts – Apr , 2013)

What’s the right way to build offline into a web application? (Jake Archibald, Mark Christian, Alex Russell and Jonas Sicking – Feb 9, 2013)

AppCache: Douchebag (Jake Archibald – Jan 20, 2013)

Application Cache And Local Storage (Scott Davis – Dec 7 , 2012)

Offline Rules (Andrew Betts – Dec 4, 2012)

Building Web Apps of the future. Tomorrow, today and yesterday. (Paul Kinlan – Nov 12, 2012)

Taking Web Apps Offline (Kevin Markman – Nov 5, 2012)

Building Offline Web Apps with HTML5 (Jonathan Stark – Jul 25, 2012)

Getting off(line): appcache, localStorage for HTML5 apps that work offline (John Allsopp – Jul 3, 2012)


Insanely fast rendering w/ Service Workers and Early Flushing (Mark Stuart – Dec 14, 2015)

Offline-First Apps with PouchDB at Node.js Interactive (Bradley Holt – Dec 9, 2015)

Developing for Offline First Mobile Experiences (Nic Raboy – Dec 2, 2015)

Building an Offline Page for (Oliver Joseph Ash – Nov 27, 2015)

At your service! – More than appcache uses for Service Workers (Salvador de la Puente González – Oct 21, 2015)

Offline First (Web) Apps (Alex Feyerke – Oct 20, 2015)

Offline-First Web Applications (Peter Müller – 2015)

Server in your Client – Service Workers’ rise to fame (Szmozsánszky István – Oct 7, 2015)

Offline-First Web Applications (Peter Müller – Jun 27, 2015)

Offline-first mobile web apps with PouchDB, IBM Cloudant, and IBM Bluemix (Bradley Holt – Jun 22, 2015)

Building Offline-Enabled Apps with PouchDB (Bradley Holt – May 20, 2015)

Naked and afraid Offline Mobile (Matt Woodward – May 18, 2015)

Offline first, the painless way (Marcel Kalveram – May 17, 2015)

noBackend e Offline First: focusing on creating experiences (pt-br) (Joselito Júnior – May 16, 2015)

HOLY SYNC: a sane approach to offline-first cross-platform data syncing (Eugenio Marletti – Apr 10, 2015)

Service Worker and the Offline Web (Lewis Cowper – Mar 7, 2015)

Service Workers on vacay… (Natasha Rooney – Mar 6, 2015)

TGIF – Offline-first (Diego Calderón – Jan 30, 2015)

ServiceWorkers and High Performance Offline Apps (AlanDalton – Jan 13, 2015)

Offline First (John Allsopp – Dec 12, 2014)

Leveraging to build for the offline state (Marcel Kalveram – Nov 24, 2014)

Let’s Take Drupal Offline! (Dick Olsson – Nov 17, 2014)

Offline-first web apps – Velocity EU 2014 (Matt Andrews – Nov 17, 2014)

Discover ServiceWorker (Sandro Paganotti – Nov 16, 2014)

Offline first ❤ (Ola Gasidlo – Oct 17, 2014)

Scaling Down: The Offline First Story (Joan Touzet – Sep 16, 2014)

Status Web Offline (Caolan McMahon – Aug 21, 2014)

Look Ma, No Connections! Building Offline-capable Web Apps with HTML5 (Bijan Vaez – Aug 1, 2014)

Say hello to offline first! (Ola Gasidlo – May 19, 2014)

Offline First (Web) Apps (Alex Feyerke – May 2, 2014)

Offline First – Made Simple! (Gregor Martynus – Apr 24, 2014)

Offline First Re-Imagining Web Development For The Real World (Caolan McMahon – Mar, 2014)


Kinto: Add synchronisation and sharing abilities to your Web application in seconds.

bottle-service: Instant web applications restored from ServiceWorker cache.

react-boilerplate: Quick setup for performance orientated, offline-first React.js applications.

Haywire: A minimal javascript library for network issues detection.

sw-toolbox: A collection of tools for service workers.

UpUp: An Offline First library designed to be the easiest way to add offline capabilities to a site.

simple-serviceworker-tutorial: A really simple ServiceWorker example, designed to be an interactive introduction to ServiceWorker.

Hyperboot: Offline webapp bootloader.

MakeDrive: A cloud-based Dropbox® equivalent for browser filesystems. Designed for use with Mozilla Webmaker tools and services. See the Mozilla MakeDrive Wiki page for background info.

ApplicationCache: HTML5 provides an application caching mechanism that lets web-based applications run offline.

IndexedDB: IndexedDB is an API for client-side storage of significant amounts of structured data and for high performance searches on this data using indexes.

ServiceWorkers: A Service Worker acts like a proxy on the client. For page requests and requests made by pages, you get a fetch event that you can respond to yourself, creating offline experiences.

localForage: Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.

remoteStorage: remoteStorage enabled apps automatically sync your data across all of your devices, from desktop to tablet to smartphone, and even your TV.

pouchdb: PouchDB is an open-source JavaScript database inspired by Apache CouchDB that is designed to run well within the browser.

Offline.js: An awesome JavaScript library to improve the experience of your app when your users lose connection.

Hoodie: Hoodie is an Offline First and noBackend architecture for frontend-only web apps on the web and on iOS.

Offline States: What show applications when we have not internet connection.


Client-Side Data Storage (by Raymond Camden)

Offline First: The book (draft) (by John Allsopp)

Pro HTML5 Programming – Chapter 12: Creating HTML5 Offline Web Applications (by Peter Lubbers, Brian Albers and Frank Salim)

Showcase Awesome offline first minute taking app built with Hoodie.

Swarm+React TodoMVC: Awesome offline implementation of TodoMVC with real-time sync.

2048: The original 2048 is a great game to pin to your homescreen. Open source software for developing world hospitals. An index of Pokémon, built as a client-side JavaScript webapp. Powered by ServiceWorker, PouchDB, virtual-dom, and web workers.

Soundslice: Learn and teach music better with interactive notation with offline mode.

Who to Follow

  • Matthew Riley: Works at mozilla, creator of localForage (localstroage, IndexedDb and WebSQL Wrapper)
  • Jake Archibald: Self described service worker fanatic, works at google helping make offline web apps a thing.


Promises are meant to be kept

Promises have state, they start as pending and can settle to:

  • fulfilled meaning that the computation completed successfully.
  • rejected meaning that the computation failed.

Promise returning functions should never throw, they should return rejections instead. Throwing from a promise returning function will force you to use both a } catch { and a .catch. People using promisified APIs do not expect promises to throw. If you’re not sure how async APIs work in JS – please see this answer first.

1. DOM load or other one time event:

So, creating promises generally means specifying when they settle – that means when they move to the fulfilled or rejected phase to indicate the data is available (and can be accessed with .then).

With modern promise implementations that support the Promise constructor like native ES6 promises:

function load(){
    return new Promise(function(resolve,reject){
         window.onload = resolve;

With libraries that support deferred (Let’s use $q for this example here, but we’ll also use jQuery later):

function load(){
    var d = $q.defer();
    window.onload = function(){ d.resolve(); };
    return d.promise;

Or with a jQuery like API, hooking on an event happening once:

function done(){
    var d = $.Deferred();
    return d.promise();

2. Plain callback:

These APIs are rather common since well… callbacks are common in JS. Let’s look at the common case of having onSuccess and onFail:

 function getUserData(userId, onLoad, onFail){ ...

With modern promise implementations that support the Promise constructor like native ES6 promises:

function getUserDataAsync(userId){
    return new Promise(function(resolve,reject){

With libraries that support deferred (Let’s use jQuery for this example here, but we’ve also used $q above):

function getUserDataAsync(userId){
    var d = $.Deferred();
    getUserData(userId,function(res){ d.resolve(res); } ,function(err){ d.reject(err); });
    return d.promise();

jQuery also offers a $.Deferred(fn) form, which has the advantage of allowing us to write an expression that emulates very closely the new Promise(fn) form, as follows:

function getUserDataAsync(userId) {
    return $.Deferred(function(dfrd) {
        getUserData(userId, dfrd.resolve, dfrd.reject);

Note: Here we exploit the fact that a jQuery deferred’s resolve and reject methods are “detachable”; ie. they are bound to the instance of a jQuery.Deferred(). Not all libs offer this feature.

3. Node style callback (“nodeback”):

Node style callbacks (nodebacks) have a particular format where the callbacks is always the last argument and its first parameter is an error. Let’s first promisify one manually:



function getStuffAsync(param){
    return new Promise(function(resolve,reject){
             if(err !== null) return reject(err);

With deferreds you can do the following (let’s use Q for this example, although Q now supports the new syntax which you should prefer):

function getStuffAsync(param){
    var d = Q.defer();
         if(err !== null) return d.reject(err); // `throw err` also works here.
    return d.promise;   

In general, you should not promisify things manually too much, most promise libraries that were designed with Node in mind have a built in method for promisifying nodebacks. For example

var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q

4. A whole library with node style callbacks:

There is no golden rule here, you promisify them one by one. However, some promise implementations allow you to do this in bulk, for example in Bluebird, converting a nodeback API to a promise API is as simple as:



  • Of course, when you are in a .then handler you do not need to promisify things. Returning a promise from a .then handler will resolve or reject with that promise’s value. Throwing from a .then handler is also good practice and will reject the promise – this is the famous promise throw safety.
  • In an actual onload case, you should use addEventListener rather than onX.

Fast Touch Events for your Web App

Try the demo

Via –

Mobile WebKits attempt to synthesize touch events into into click events. These same browser engines also have a double-tap-to-zoom function. This brings up the issue of distinguishing between a tap and double tap. What is a WebKit to do?

The answer is pretty simple. WebKit adds a small delay of 300 milliseconds after a single tap to see if you will tap a second time. If no second tap happens within 300 milliseconds, the gesture is interpreted as a single tap which is subsequently translated into a “click” event.


You already know that you can disable pinch and tap zooming in your app, provided you have designed your app to have nice, large buttons and text. Unfortunately, even after you do this, WebKit maintains the 300 millisecond delay after a single tap. To make matters worse, the delay is only triggered on fast taps. If you touchstart, pause briefly, then touchend you will experience no delay. Most users will tap fast enough to experience the delay some, if not most, of the time. This small delay can create a perceived slowness in your app, and therefore, it must be eliminated with extreme prejudice.

Libraries like fastclick will eliminate this delay for you, and will also take care of some tricky edge cases, but basic fast tap handling is pretty easy. The example code below demonstrates fast tap handling with the jQuery special event API, but the process will be similar with most other JavaScript event-handling libraries.

$.event.special.tap = {
  setup: function() {
    var self = this,
      $self = $(self);

    // Bind touch start
    $self.on('touchstart', function(startEvent) {
      // Save the target element of the start event
      var target =;

      // When a touch starts, bind a touch end handler exactly once,
      $'touchend', function(endEvent) {
        // When the touch end event fires, check if the target of the
        // touch end is the same as the target of the start, and if
        // so, fire a click.
        if (target == {
          $.event.simulate('tap', self, endEvent);

This is the basis for any sort of fast tap handling. In some cases, this may even be good enough. However, there are many ways to make this more robust.

Time Threshold

If a user starts a touch, holds, and then releases after one second, is that a tap? Maybe not, here’s how you can add a configurable time threshold to abort a tap event if the time between touchstart and touchend is too long.

$.event.special.tap = {
  // Abort tap if touch lasts longer than half a second
  timeThreshold: 500,
  setup: function() {
    var self = this,
      $self = $(self);

    // Bind touch start
    $self.on('touchstart', function(startEvent) {
      // Save the target element of the start event
      var target =,

      function removeTapHandler() {
        $'touchend', tapHandler);

      function tapHandler(endEvent) {

        // When the touch end event fires, check if the target of the
        // touch end is the same as the target of the start, and if
        // so, fire a click.
        if (target == {
          $.event.simulate('tap', self, endEvent);

      // Remove the tap handler if the timeout expires
      timeout = setTimeout(removeTapHandler, $.event.special.tap.timeThreshold);

      // When a touch starts, bind a touch end handler
      $self.on('touchend', tapHandler);

Distance Threshold

If the user starts a touch, moves 200 pixels to the left, then releases, is that a tap? Maybe not. Here’s how you can add a configurable distance threshold to abort a tap event if the user moves his or her finger too far.

$.event.special.tap = {
  // Abort tap if touch moves further than 10 pixels in any direction
  distanceThreshold: 10,
  // Abort tap if touch lasts longer than half a second
  timeThreshold: 500,
  setup: function() {
    var self = this,
      $self = $(self);

    // Bind touch start
    $self.on('touchstart', function(startEvent) {
      // Save the target element of the start event
      var target =,
        touchStart = startEvent.originalEvent.touches[0],
        startX = touchStart.pageX,
        startY = touchStart.pageY,
        threshold = $.event.special.tap.distanceThreshold,

      function removeTapHandler() {
        $'touchmove', moveHandler).off('touchend', tapHandler);

      function tapHandler(endEvent) {

        // When the touch end event fires, check if the target of the
        // touch end is the same as the target of the start, and if
        // so, fire a click.
        if (target == {
          $.event.simulate('tap', self, endEvent);

      // Remove tap and move handlers if the touch moves too far
      function moveHandler(moveEvent) {
        var touchMove = moveEvent.originalEvent.touches[0],
          moveX = touchMove.pageX,
          moveY = touchMove.pageY;

        if (Math.abs(moveX - startX) > threshold ||
            Math.abs(moveY - startY) > threshold) {

      // Remove the tap and move handlers if the timeout expires
      timeout = setTimeout(removeTapHandler, $.event.special.tap.timeThreshold);

      // When a touch starts, bind a touch end and touch move handler
      $self.on('touchmove', moveHandler).on('touchend', tapHandler);

Other considerations

Reading the fastclick source is the best way to understand all the nuances of fast click handling on touch devices. Fastclick will take care of some quirks in older mobile browsers, different requirements for certain input elements, as well as eliminating “phantom” clicks.