Handling click and touch events on the same element

I’m starting to feel behind the curve. I started receiving feedback that some
clickable elements on my social networks were not working on touch devices.
Without much thought, I went ahead and added touchstart along side of click
to bind both events:

$(document).on('click touchstart', '.feeny', function(e) {
  alert('Believe in yourselves. Dream. Try. Do good.'

“Problem solved!”, I thought. This resolved the issue with form submit buttons
but not hearts. Hearts persist on the page when clicked. Things worked fine on
the desktop but tapping a heart on your phone would fire both click and
touchstart events. This would heart and immediately unheart the item.

I then did some research and polled my friends to see how they would do it. My
buddy Khary suggested sniffing the browser for touch capabilities and
setting the event handler accordingly. The interwebs corroborated this and I
proceeded to use a variable for the event:

var clickEvent = (function() {
  if ('ontouchstart' in document.documentElement === true)
    return 'touchstart'
  else
    return 'click'
})();

Worked great on my desktop and Android phone. Even worked on iOS which was the
platform that was double firing. Code went live. NEXT PROJECT!

Over the next two weeks I noticed the occasional “complaint status” about some
click events not working. Nothing formal was reported so I assumed these were
edge cases and did not action on them. I continued to research and eventually a
formal bug report came in.

I learned about a third device I was not considering, the touchscreen laptop.
It’s a hybrid device that supports both touch and click events. Binding one
event means only that event be supported. Does that mean someone with a
touchscreen and mouse would have to explicitly touch because that’s the only
event I am handling?

Binding touchstart and click seemed ideal to handle these hybrid devices.
To keep the event from firing twice, I added e.stopPropagation() and
e.preventDefault() to the callback functions. e.stopPropagation() stops
events from “bubbling up” to their parents but also keeps a second event from
firing. I included e.preventDefault() as a “just in case” but seems like it
could be omitted.

The code’s been live for a few days but I was only able to confirm that things
are working on my devices. Until I can track down a user with a touchscreen
laptop I won’t know for sure. Fortunately I have already seen a “praise status”
about the problem “fixing itself” so the solution may be a hit.

Josh Sherman - The Man, The Myth, The Avatar

About Josh

Husband. Father. Pug dad. Musician. Founder of Holiday API, Head of Engineering and Emoji Specialist at Mailshake, and author of the best damn Lorem Ipsum Library for PHP.


If you found this article helpful, please consider buying me a coffee.