A lightweight normalized tap event

Overview

🚫 Retired: Tappy!

Per our unmaintained repository status documentation this repository is now retired and is no longer accepting issue reports or pull requests. The touch delay in web browsers has been solved natively! Hooray 🎉 !

Filament Group

Tappy is a minimal normalized tap event that works with touch, mouse, keyboard, and probably other inputs too.

©2013 @scottjehl, Filament Group, Inc. Licensed MIT

Why

Tappy allows you to bind to a tap event like you would any other user interaction, like click. The advantage of usting Tappy's tap event over click is that it will allow you to execute code immediately on touch devices, eliminating the 300ms delay that click events have on platforms like iOS. Once bound to an element, Tappy's tap event will fire upon touch or other traditional interactions like mouse click, pressing the enter key, and more.

How-to

Tappy requires jQuery, or a similar framework of matching API conventions.

To use, include tappy.js in your page, select an element and bind to a tap event.

$( "a.my-link" ).bind( "tap", function( e ){ 
  alert( "tap!" );
}); 

In binding to the tap event, you'll be automatically preventing the browser's default click handling on the element, so be sure to handle that tap responsibly.

To use tappy to create fast-click navigation, you could do something like this on domready:

$( "a" ).each( function(){
  var href = $( this ).attr( "href" );
  if( href.indexOf( "#" ) !== 0 ){
				$( this ).bind( "tap", function(){
					window.location.href = this.href;
				});
			}
} );

Unbinding

$( "a.my-link" ).unbind( "tap" ); 

Notes:

This plugin makes several assumptions that may not work well for your project, but we've found them easy enough to work around.

Tappy works best when bound directly to a tappable element. In its current state, we don't recommend using it with event delegation due to the way it prevents default event behavior. That might change in a future update.

This plugin is built using a very limited portion of jQuery's API in attempt to be compatible with slimmer libraries that share jQuery's syntax. That's why it monkey-patches bind for example, rather than using the Special Events API. That said, we could make those changes, but this is working pretty well for our admittedly specific needs at the moment.

What Not To Do

  • Do not bind a child node to the tap event when a parent node is already bound. Ex:
">
<div class="foo">
    <div class="bar">
    div>
div>
$( ".foo" ).bind( "tap", function(){
    foo();
});

$( ".bar" ).bind( "tap", function(){
    bar();
});

If you do this, when the .bar element is tapped on, due to the nature of how the event is normalized, the callback function for bar will be called twice.

  • Do not bind a tap event more than once to a single element. Ex:
Don't Push Me">
<button class="btn-classy">Don't Push Mebutton>
$( ".btn-classy" ).bind( "tap", function(){
    console.log( "I'm so classy" );
});

$( ".btn-classy" ).bind( "tap", function(){
    console.log( "Cuz I'm close to the... edge." );
});

If you do this, when the

Comments
  • Documentation should suggest .on instead of .bind

    Documentation should suggest .on instead of .bind

    The documentation suggests using .bind() to attach Tappy to elements; however, from the jQuery docs as of jQuery 1.7, .on() is now the preferred way to do this. .bind() still works, but it is run through .on(), and so incurs a miniscule performance penalty.

    http://api.jquery.com/bind/ - docs http://stackoverflow.com/questions/11847021/jquery-bind-vs-on - a question about which one, as I wondered about .bind() when I read it here and this was the first thing I read.

    Thanks :)

    opened by mikehdt 5
  • Hello, about jquery clone(true)

    Hello, about jquery clone(true)

    First, it works great on iOS device! (Thank you so much) However, when I'm using deep clone, it seems to fire twice.

    Here's the circumstance: $('#a').on('tap', function(){ console.error('a'); }); $('#a').clone(true).appendTo($('body'));

    it works with the first element, but the cloned element fires twice though.

    Is there a workaround to deal with clone??

    opened by awesomejerry 4
  • vanillaJS version

    vanillaJS version

    I'm not one of those jQuery haters, but tappy is so small that it could be handy for projects that don't have jQuery as a dependency.

    I'd gladly contribute a vanillaJS version, especially that I know the size of the testing infrastructure you have access to. BTW, are you going to write a test suite for tappy?

    opened by naugtur 4
  • Prevents checking a checkbox with click or spacebar on focus

    Prevents checking a checkbox with click or spacebar on focus

    Tappy seems to prevent selection of a checkbox. Doesn’t work with a normal click or hitting the spacebar when the checkbox is focused.

    I checked a test case into index.html on the https://github.com/filamentgroup/tappy/tree/checkbox-issue branch.

    opened by zachleat 4
  • Possible to discern when a user shift/ctrl/cmd clicks a link?

    Possible to discern when a user shift/ctrl/cmd clicks a link?

    Would it be easy enough for tappy to discern between 'normal' taps and ones with a modifier key? I realise this isn't an everyday occurrence but since putting tappy on my blog I had someone complain I was click-jacking shift+click, which in their Chrome should have opened the link in a new tab (but opens in the same one with Tappy present).

    My JS-fu is weak so I'm short on code offerings :(

    I'm thinking along these lines (semi-pseudo code):

    if (!(e.which > 1 || e.shiftKey || e.altKey || e.metaKey || e.ctrlKey)) {
            // Tappy starts here
    }
    // Source: http://www.jacklmoore.com/notes/click-events/
    
    opened by benfrain 3
  • Context menus on tappy links in iOS open context menu but also already follow link

    Context menus on tappy links in iOS open context menu but also already follow link

    When using tappy on links, long-pressing a link in Safari/iOS opens the context menu - as soon as the finger is lifted off the screen, the link is followed, despite the context menu still being open.

    See https://www.youtube.com/watch?v=P_YJe1MQ4m8

    Arguably, this smells like a bug in iOS - testing the event flow using http://patrickhlauke.github.io/touch/tests/event-listener_link.html it seems that when context menu is shown, Safari/iOS doesn't consistently fire touchcancel; in fact, if you keep the finger pressed, you can actually still scroll the page underneath the context menu and it fires touchmove events, and sometimes it then fires touchend if you lift the finger while the context menu is shown. Not sure if this is something that can be caught/prevented by tappy though...

    opened by patrickhlauke 2
  • Unbind?

    Unbind?

    I'm attempting to use this in conjunction with enquire.js, as part of an off-canvas mobile navigation pattern. When my query no longer matches, I want to unbind the tap event and resume typical link behavior.

    Unbinding the event seems to remove all of the other functions I was calling on tap, so I know it's working partially - however, the default link behavior still doesn't resume.

    opened by evanhuntley 2
  • Don't block other click handlers

    Don't block other click handlers

    This keeps Tappy from preventing other click handlers that might be bound to something. On a current project, for example, we have an analytics script that attaches a click handler to any element with a certain class. Tappy was preventing that click handler from being called.

    This change makes trigger trigger a click event, but passes an extra argument that end then checks for, so that it doesn't get stuck in a loop. The current implementation is a little greasy, and could probably use a some refactoring to be clearer as to the function of passing false around.

    opened by athaeryn 2
  • Tap Event delegation

    Tap Event delegation

    What if i want to use event delegation, Smth like $(document).on('tap','.my-elem',function(){}); but inside .my-elem there's another element also attached for tapping? Sample markup and script

    <div class="my-elem">
        <button class="my-button" >Tap me </button>
    </div>
    
    $('.my-button').on('tap',function (){ alert('Button tapped');});
    $(document).on('tap','.my-elem',function(){ alert('Div tapped');});
    

    try this code and you will find that when you tap on the button there's two alert about Button tapped and none of Div tapped. I found the only one way to fix this totally move to on/off jquery functions:

    var tap = function( $els,selector ){
    ...
               function trigger( e ){
                    var el = (selector &&  $(e.target).is(selector))?e.target:$el[0];
                    $( el ).trigger( "tap", [ e, $( el ).attr( "href" ) ] );
                }
               ...
              $el
                    .on( "touchstart.tappy MSPointerDown.tappy",selector, start )
                    .on( "touchmove.tappy MSPointerMove.tappy",selector, move )
                    .on( "touchend.tappy MSPointerUp.tappy",selector, end )
                    .on( "click.tappy",selector, end );
             ...
    };
    var untap = function( $els,selector ){
            return $els.off( ".tappy",selector );
        };
    ...
    if( $.event && $.event.special ){
            $.event.special.tap = {
                add: function( handleObj ) {
                    tap( $( this ),handleObj.selector );
                },
                remove: function( handleObj ) {
                    untap( $( this ),handleObj.selector );
                }
            };
        }
    
    

    Notice the selector param.

    opened by Hiller 1
  • VoiceOver

    VoiceOver

    VoiceOver 'click' does not trigger 'tap'.

    In Voice Over (VO) on iOS devices, 'Tap' is never fired.

    Replication:

    1. Bind an element to 'tap'
    2. Turn on Voice Over
    3. Double tap to 'click'

    Expected:

    1. Event handler should fire

    VO does a click and somewhere, that event gets lost. The workaround was to bind both events (click, tap) and then throw 'click' away if 'tap' is recognized. If tap is not found, it goes ahead and fires the click event.

    Solution:

    My recommendation would be to bind the click when the 'tap' is bound and do some checks internally. This is the only way as we can know when voiceover is being used. Will be working on a fix.

    opened by leifdejong 1
  • Binding with mouseover?

    Binding with mouseover?

    Hi,

    I use the binding like so:

    // bind tappy
    $( 'a' ).each( function(){
        var href = $( this ).attr( "href" );
        if (typeof href != 'undefined'){
            if( href.indexOf( "#" ) !== 0 ){
                $( this ).bind( "tap", function(){
                    window.location.href = this.href;
                });
            }
        }
    }); 
    

    I have some dropdown menus displaying on mouseover, wich have links in the first level as well. Is there any change to 'slow down' the response time, so that my submenus can be used and not allways the first level link is triggered?

    Thanks in advance!

    opened by sixtyseven-multimedia 1
Releases(v0.1.2)
Owner
Filament Group
Filament Group
A simple handle tap and hold action for Svelte/SvelteKit.

Svelte Tap Hold Minimalistic tap and hold component for Svelte/SvelteKit, see demo here. Installation // Using Yarn to install yarn add --dev svelte-t

Binsar Dwi Jasuma 9 Dec 8, 2022
A simple tap test runner that can be used by any javascript interpreter.

just-tap A simple tap test runner that can be used in any client/server javascript app. Installation npm install --save-dev just-tap Usage import cre

Mark Wylde 58 Nov 7, 2022
io-ts Typed Event Bus for the runtime of your Node.js application. A core for any event-driven architecture based app.

Typed Event Bus Based on io-ts types, this bus provides a handy interface to publish and consume events in the current runtime of the Node.js process.

Konstantin Knyazev 3 May 23, 2022
'event-driven' library aims to simplify building backends in an event driven style

'event-driven' library aims to simplify building backends in an event driven style(event driven architecture). For message broker, light weight Redis Stream is used and for event store, the well known NoSQL database, MongoDB, is used.

Sihoon Kim 11 Jan 4, 2023
A lightweight jQuery custom scrollbar plugin, that triggers event when reached the defined point.

Scrollbox A lightweight jQuery custom scrollbar plugin, that triggers event when reached the defined point. Demo Page Table of contents Browser compat

null 15 Jul 22, 2022
Examples of how to do query, style, dom, ajax, event etc like jQuery with plain javascript.

You (Might) Don't Need jQuery Frontend environments evolve rapidly nowadays and modern browsers have already implemented a great deal of DOM/BOM APIs

NEFE 20.3k Dec 24, 2022
Work around some mobile browser's 300ms delay on the click event.

jQuery fastClick plugin Work around the 300ms delay for the click event in some mobile browsers (e.g. Android and iOS). Code based on http://code.goog

Dave Hulbert 132 Jul 6, 2020
An event emitter that allows you to manage your global state

Thor Event Emitter Event emitter to manage your state. An event emitter that allows you to manage your global state. Instead of using global giant obj

Jalal 6 Apr 18, 2022
Event scheduler is a simple app for viewing the events happening around you

Event scheduler is a simple app for viewing the events happening around you. User can also create their event and include a location. Location can also be marked as hidden(strictly by IV). Built with React and Styled Components

Anselem Odimegwu 3 Mar 29, 2022
The invoker based on event model provides an elegant way to call your methods in another container via promisify functions

The invoker based on event model provides an elegant way to call your methods in another container via promisify functions. (like child-processes, iframe, web worker etc).

尹挚 7 Dec 29, 2022
🏳️‍🌈 event calendar

alman-akka :rainbow-flag: event calendar Frontend The frontend of this app uses NextJS and Node 16 together with Yarn 1.x as a package manager. Develo

null 3 Mar 10, 2022
An event-driven architecture wrapper for Wechaty that applies the CQS principle by using separate Query and Command messages to retrieve and modify the bot state, respectively.

CQRS Wechaty An event-driven architecture wrapper for Wechaty that applies the CQS principle by using separate Query and Command messages to retrieve

Wechaty 3 Mar 23, 2022
Real-time event collaborating

Smartlist Collaborate Collaborate on your events in real-time! An product by Smartlist ?? This product is still in development, and some features mig

Smartlist 2 Mar 17, 2022
Timers for Lost Ark bosses, islands, events, wandering merchants and more! Never miss an event again.

Timers for Lost Ark bosses, islands, events, wandering merchants and more! Never miss an event again. LostArkTimer.app Website Website Features Event

Joshua Kuan 28 Oct 17, 2022
Analysing and storing r/Place 2022 event

Caching r/Place 2022 This project is live at place.thatguyalex.com. Running scraper locally Install Python and all dependencies from scraper.py import

Alex Tsernoh 157 Dec 16, 2022
The /r/place Atlas is a project aiming to catalog all the artworks created during Reddit's 2022 /r/place event.

The 2022 Place Atlas The /r/place Atlas is a project aiming to catalog all the artworks created during Reddit's 2022 /r/place event. This project was

Place Atlas 397 Dec 28, 2022
awsrun 189 Jan 3, 2023
An event management system.

What is the purpose? It's a very tiny library for publish/subscribe(pubsub) operations. There's no dependency. It's only 933(gziped: 437) byte. Writte

Can Küçükyılmaz 7 Mar 2, 2022
💊 Event-driven DOM programming in a new style

Capsule v0.5.3 Event-driven DOM programming in a new style Features Supports event-driven style of frontend programming in a new way. Supports event d

capsid 21 Oct 1, 2022