Faster Click Events

Upon researching ways to remove the click delay for mobile devices, I found an article from the Google Developers website and it seems as though they have solved the dreaded 300ms click delay with some tried and true JavaScript. I know, 300ms is not a long time but it makes a big difference in how an application feels to the user. A web application should feel as close to a native app as possible. HTML5 allows developers to create web applications that feel like native apps on mobile devices. What’s a native app? It’s an application developed for a specific hardware platform and has been compiled into the machine language of that device. A web app has to be interpreted by the browser before it is executed where a native app does not, which is why developers are always looking for ways to make web apps faster.

An application should feel responsive while avoiding interference with current logic

This click event produces a 300ms delay on a mobile device because the mobile browser waits to see if there is a double tap. The majority of tap events on a mobile device are single clicks and users should not have there time wasted. Quite frankly, this does not provide a good user experience and does not give the user the feeling that your website has a good response time, whether they realize it or not.

A touchend event does not produce a delay and is the better way to handle mobile click events but, there are a couple of stipulations for this action. A touchend event should not be fired if another part of the users screen is tapped or if the actual button is tapped and then the user scrolls the page. Monitoring touchstart and touchmove events usually solves any problems associated with accidental touch events involving clicks or scrolling. We can solve the latter problem by adding an onclick handler to the button as well. Doing so will allow the browser to properly treat it as a button, and our touchend handler will ensure that the button is still fast. Also, the presence of an onclick handler serves as a good fallback for browsers that don’t support touch events.

Once the onClick handler is added, the dreadful 300ms delayed click event will still fire causing a double click event. To prevent this occurrence, simply calling preventDefault on the touchStart event will remove any extra clicks or scrolling. Also, a click event listener needs to be added to the body that determines whether a current click is from a tap that was already handled, in which case preventDefault and stopPropagation are called.


//Construct the FastButton with a reference to the element and click handler

google.ui.FastButton = function(element, handler) {  
  this.element = element;  
  this.handler = handler;  
  element.addEventListener('touchstart', this, false);  element.addEventListener('click', this, false);
  google.ui.FastButton.prototype.handleEvent = function(event) {  
    switch (event.type) {    
    case 'touchstart': this.onTouchStart(event); break;    
    case 'touchmove': this.onTouchMove(event); break;    
    case 'touchend': this.onClick(event); break;    
    case 'click': this.onClick(event); break;  

//Call stopPropagation

google.ui.FastButton.prototype.onTouchStart = function(event) {  
  event.stopPropagation();  this.element.addEventListener('touchend', this, false);  
  document.body.addEventListener('touchmove', this, false);  this.startX = event.touches[0].clientX;  this.startY =    event.touches[0].clientY;};

When a touchmove event is invoked, check if the user has dragged past the threshold of 10px.

google.ui.FastButton.prototype.onTouchMove = function(event) {  
  if (Math.abs(event.touches[0].clientX - this.startX) > 10 || Math.abs(event.touches[0].clientY - this.startY) > 10) {    

//Invoke the click handler

google.ui.FastButton.prototype.onClick = function(event) {  
    this.reset();  this.handler(event);  
    if (event.type == 'touchend') {    
      google.clickbuster.preventGhostClick(this.startX, this.startY);  

google.ui.FastButton.prototype.reset = function() {  
  this.element.removeEventListener('touchend', this, false);  
  document.body.removeEventListener('touchmove', this, false); 

//Call preventGhostClick to prevent click events that happen within 25px of the provided x, y coordinates in the next 2.5s.

google.clickbuster.preventGhostClick = function(x, y) {  
  google.clickbuster.coordinates.push(x, y);  
   window.setTimeout(google.clickbuster.pop, 2500);};google.clickbuster.pop = function() {  
     google.clickbuster.coordinates.splice(0, 2);

//Call stopPropagation and preventDefault to stop links from being activated

google.clickbuster.onClick = function(event) {  
  for (var i = 0; i < google.clickbuster.coordinates.length; i += 2) {    
    var x = google.clickbuster.coordinates[i];    
    var y = google.clickbuster.coordinates[i + 1];    
      if (Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {      
}  }};

document.addEventListener('click', google.clickbuster.onClick, true);google.clickbuster.coordinates = [];

Article Update

An update to this article from Jake Archibald:
300ms tap delay, gone away

Get in touch

Contact Me
(941) 416-0874


Mon - Fri 9am - 9pm
Sat 10am - 2pm