Fixing jQuery Click Events for the iPad

December 22, 2010

I recently had a situation where I had built something for a client, tested it, etc and made it live. It worked as intended on ‘normal’ computers, but my boss, who has an iPad, found that it didn’t work at all on the iPad. Well, I say it didn’t work at all, it kinda worked, although it very definitely didn’t work as intended.

The thing in question was an animated hero panel, with navigation buttons along the side, which enabled the visitor to see different panels of content by clicking the buttons. Pretty standard stuff, nothing funky, nothing crazy, just bread ‘n’ butter jQuery, so you can imagine my surprise when it didn’t work on the iPad.

What was actually happening was that a single click was being treated as a hover, and so the active style was being applied to the navigation buttons when one of them was pressed a single time. If then pressed a second time, the animation/content change was being applied. Interesting.

Fixing the issue turned out to be surprisingly easy, we just need to sniff the userAgent string and look for iPad. Yes, I just said sniff the userAgent. I know, right?! We stopped doing userAgent-based browser detection years ago. But that indeed was the advice I found while browsing the developer docs over at apple.com, and it worked, which is of course the main thing.

The code turned out to be as simple as this:

var ua = navigator.userAgent,
    event = (ua.match(/iPad/i)) ? "touchstart" : "click";

$("theElement").bind(event, function(e) {
    //do shit here
}

We just try to find the string iPad in the userAgent string (specifying the case-insensitive flag), and set the event to touchstart if it is found, or click if it isn’t. We then just pass the event variable to the jQuery bind() method and supply an anonymous function as we normally would.

Changing the code to the above from what it was originally, $(theElement).click(function() { });, fixed the problem entirely, and the intended behaviour of triggering the animation/content change with a single click (or touch) was restored.

39 Responses to “Fixing jQuery Click Events for the iPad”

  1. [...] This post was mentioned on Twitter by Dan Wellman. Dan Wellman said: fixing click events for the iPad when using jQuery: http://is.gd/jfXBm [...]

  2. Peter Coles says:

    Nice trick! Seems like this should be applied to the iPhone as well?

    Also, this vaguely reminds of a jquery fadeIn speed trick from a Paul Irish video: http://www.youtube.com/watch?v=i_qE1iAmjFg#t=18m

  3. Dan Wellman says:

    Thanks :D

    Yeah, it should work just as well on the iPhone with a little tweak that looks for ‘iPhone’ as well as ‘iPad’ in the user agent string…

  4. Darren says:

    Thanks for posting this.

    I was struggling for an answer to this double click issues for a few days now!

    cheers!

    -d

  5. Frank says:

    In my case I was using .click(function() …) on a select tag which worked ok on everything except ipad and iphone. I simply changed the ‘.click’ to ‘.change’ and it fixed the problem.

  6. Dan Wellman says:

    That’s a great tip Frank, thanks for sharing :) It would only work for elements that fire a change event, such as form controls, but useful nontheless

  7. pk says:

    thanks it worked for meto …but now IE browser is giving the JS error, this obeject is not supported in IE. and error is pointing to line which i added

  8. Dan Wellman says:

    which line does it refer to?

  9. Cameron says:

    Why not just run:
    $(“element”).bind(“click touchstart”, function(){
    alert(‘Code here’);
    });
    Since the click event wouldn’t get registered on devices that are interpreting it as a hover. Yes, it’s not the most efficient method, but it would solve the problem for all iOS devices and potentially android devices (haven’t tested if they are affected by this issue).

  10. Dan Wellman says:

    Have you tested? If this works it would be pretty cool, although as I mentioned in the post, it isn’t that iPad doesn’t fire click events, just that it handles them differently (e.g. firing them on a double click insteasd of a single click), so binding to both click and touchstart may have some undesired/unforseen effects…

    I guess it’s swings and roundabouts – as you say this code isn’t the most efficient, i.e. it registers two events when only one is required, however, it does (if it works) enable us to move away from sniffing the user-agent :)

    I’d be interested in testing it, could be a good excuse to finally get an iPad!

  11. Bob Glasser says:

    Great great great easy fix. i was getting a little frustrated trying a few things and this instantly fixed the issue. thanks for posting.

    ps- works just fine if you change it to iPhone as well

  12. Kevin says:

    Could someone show how i would insert this code to get my nav buttons working on ipad,ipod and iphone at this site.
    http://www.neteffectrollon.com Thanks!

  13. Dan Wellman says:

    You need to put it inside the jQuery document ready function (if you’re using it) but before any event handlers that rely on the click (or touchstart) event

  14. Brad Koehn says:

    This worked perfectly! Great job! Thanks for sharing…

  15. christophe says:

    Hi Dan

    This seem exactly what I need. I tried to implement this solution on an Image map (the exact same one as here http://www.svennerberg.com/examples/imagemap_rollover/index_jquery.html)

    I just change their JS event to the following but IPAD is having none of it. Any idea ?

    Thanks

    C

    var ua = navigator.userAgent,
    event = (ua.match(/iPad/i)) ? “touchstart” : “click”;

    $(this).bind(event, function(e) {
    e.preventDefault();
    var country_id = $(this).attr(‘id’).replace(‘area_’, ”);
    alert(‘You clicked ‘ + country_id);
    });

  16. Christeen Figura says:

    I saving the pic but it’s not showing up other than in the album cover. Do you know what’s up?

  17. Jordan Silva says:

    That works very well!! Thanks

  18. Darcy Bross says:

    I encountered this issue also but took a slightly different approach as we happened to be using Modernizr alongside jQuery. Just used the test for touch capability instead and pretty much any device gets covered:

    if(Modernizr.touch){
    event = “touchstart”;
    } else {
    event = “click”;
    }
    $(“theElement”).bind(event, function(e) {
    //do shit here
    }

  19. Sam says:

    There is an issue (tested on iPad 3) where if the user touches one of these objects with the click/touch handler attached when scrolling. I.e., the user places their finger on the screen to begin a scroll gesture, BUT, the touch event fires immediately.

    So, if you have a button with the touchstart event set, and the user happens to touch this when scrolling, the event will fire even though it was not the users intention.

    ‘touchend’ should be used to avoid this.

  20. Dan Wellman says:

    Great tip, thanks Sam!

  21. The use of touchend suggested by Sam also can cause trouble. The possible solution is to compare the positions at touchStart and touchend occured and also the timegap between them. If those satisfies to be a ‘tap’ then do the logic for tap.

    Another opinion to bind both touchstart and click on same event can also be buggy. touchstart gets fired as soon as finger is touched. click is an interface event that will be fired after the finger is pulled back and gesture is completed. So this might lead to triggering the handler twice.

    Possible solution is to retain your idea of checking the event type, but using the touch tester by Modernizer [if(!!('ontouchstart' in window) )] will cover more devices. Then instead of just using touchstart some logic to determine tap accurately can be implemented.

  22. Hugh says:

    Do you hate Android? Because you just ditched millions of Android devices with this solution. Try this instead of sniffing for iPad/iPod in the UA:

    var isTouchSupported = “ontouchend” in document;

  23. Dan Wellman says:

    Do I hate what? Ha ha, just kidding. No I don’t hate Android. This post is what 18 months old now? There are much better ways of doing this now, and you’re right, it is wrong to exclude Android, or any popular platform :)

  24. pistachio says:

    Thanks for the post it helped me big time, thanks alot again :)

  25. huangrenjie says:

    Hi, this code will work but I have some extra consider that this will make some potential issue because ontouchstart in IPAD fires once your figure touch the button, and the it same as the mouse down event in desktop in my mind.And in IPAD/IPHONE, when you use if you will find some conflict with touchmove event. I think the appropriate logic for figure click is. 1. figure down touch the object 2. figure up and with touch the same object then fire the function if not cancel.If I have anything wrong or you want to discuss more, please send me email.
    Thanks.

  26. Ruchir says:

    Thanks.. works like a charm.

  27. dan says:

    this might work but is not a real solution, why some links with jquery click even will work and other don’t, better focus on that, and find a fix that way.

  28. [...] schlicht die Infos dieser Seite, um für das iPhone und das iPad das touchstart Event zu verwenden. http://www.danwellman.co.uk/fixing-jquery-click-events-for-the-ipad/ (function($){ var options = {"info_link":"http://heise.de/-1333879","txt_help":"Wenn Sie diese [...]

  29. Jafar says:

    You can use jQuery .on method and bind both click and touchstart

    .on(‘click touchstart’,'#thing’,function(e){})

    Here is a fiddle: http://jsfiddle.net/hyxdc/

  30. Alex says:

    Excellent tip, thanks a lot :)

  31. [...] drove me nuts. I found a person that also had a click issue posting about their oddity. Slightly different for them, but the fix is [...]

  32. Minh Ai says:

    Thanks for your posts!!! ^^

  33. Pete Jones says:

    You might be interested in https://github.com/ftlabs/fastclick

    which handles the problem of the delay (300ms) causing some events to fire twice (like AJAX calls).

  34. Eytan Chen says:

    binding the “touchstart” event is annoying, as the user can’t scroll the page from the element the event was bind to.
    I found another global solution, which works great as much as I tested.
    After detecting mobile or tablet, i then trigger an elements click event on hover:

    $(“a, div”).hover(
    function(e){
    e.preventDefault();
    $(this).trigger(“click”);
    }
    );

  35. 靴 激安 says:

    メンズサンダルブランド 靴 激安 http://www.baidulen.com/

  36. mani says:

    great…..its worked for me

  37. Steven Luong says:

    i think we can use multiple events trigger for 1 element
    $(“element”).bind(‘touchstart click’, funtion(){
    //do somthing here
    });

  38. Dan McNulty says:

    You could just bind the handler to both in this case:

    $(“theElement”).bind(‘touchstart click’, function(e) {
    //do shit here
    }

  39. Howdy! I’m at work surfing around your blog from my new iphone!
    Just wanted to say I love reading your blog and look forward tto all your posts!
    Keeep up the excellent work!

Leave a Reply

My Books