Does fastclick work with ReactJS's event system? It doesn't seem to be taking when run through Cordova onto iOS or Android. If not, is there another way of getting the same results. My app has no double-tap functionality so I'd like to remove that delay across the board, if possible...
6 Answers
Edit
Facebook decided to not add support for defining custom event types and recommend you to use something like react-tappable so you can write something like <Tappable onTap={}>
.
Facebook's working on a solution in the form of TapEventPlugin
, but it won't be made available until they make some decisions.
If you're reading this you're probably working on a project that can't wait until they figure out how they want to publish it.
This repo is for you: https://github.com/zilverline/react-tap-event-plugin
When Facebook solves #436 and #1170, this repo will disappear.
This solution works for React 0.14.x and 15.x.
npm i -S react-tap-event-plugin
Example of usage:
var React = require("react");
var ReactDOM = require("react-dom");
injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();
var Main = React.createClass({
render: function() {
return (
<a
href="#"
onTouchTap={this.handleTouchTap}
onClick={this.handleClick}>
Tap Me
</a>
);
},
handleClick: function(e) {
console.log("click", e);
},
handleTouchTap: function(e) {
console.log("touchTap", e);
}
});
ReactDOM.render(<Main />, document.getElementById("container"));
Note that with the injector, you will probably need to use only onTouchTap
(and not onClick
anymore).

- 8,423
- 5
- 40
- 39
-
FYI, onTouchTap works as a click (for non touchscreen). – MoOx Dec 01 '15 at 13:44
-
So just to be clear should I use react-tap-event-plugin or React-Tappable now? – Kimmo Hintikka Sep 26 '16 at 14:08
-
2Both works, but react-tappable seems a more reasonable choice. No monkey patching. – MoOx Sep 26 '16 at 22:25
-
Thanks, probably going that way as react-tap-event-plugin seems to break down with react@15.3.2 – Kimmo Hintikka Sep 27 '16 at 08:35
-
Is this solution required only for mobile browsers? – Jjang Oct 23 '17 at 20:41
I got FastClick to work with React, in a Webpack project. A few things seem finicky but it mostly works. (Update: only a toggle switch that was simulating clicks on a hidden checkbox was finicky -- that would be a problem regardless of React). Here's how I turned it on:
npm install -S fastclick
In main.jsx
:
import FastClick from 'fastclick';
window.addEventListener('load', () => {
FastClick.attach(document.body);
});
So even if you're not using Webpack or Browserify, I'm guessing as long as you can run the load event listener, you'll be fine.

- 7,885
- 5
- 55
- 61
-
4This worked perfect for me. FWIW, in my isomorphic react app built with webpack, I had to stub out the fastclick module on the server build with `new webpack.NormalModuleReplacementPlugin(/fastclick$/i, 'node-noop')` – Federico Jun 03 '15 at 23:53
-
-
4Soo... I just found out that unfortunately this solution doesnt play nicely with using React's onClick handlers. It only works for your generic html elements -- anchors, buttons, etc. Here's the best I've found: https://github.com/zilverline/react-tap-event-plugin – Federico Jun 04 '15 at 18:25
-
What behavior are you seeing? I haven't had any problem with `onClick` handlers. – Andy Jun 04 '15 at 21:21
-
Are you creating a React component with an `onClick` prop but not passing it down to the component whatever `render()` returns, so that it ultimately winds up on a real HTML component? As far as I know, an `onClick` handler on a React component won't do anything, you have to pass it down to an HTML element. – Andy Jun 04 '15 at 21:29
We recently created a React component that is similar to fastclick, except that it’s much simpler and requires a manual callback. It’s pretty short so I’ll post it here:
React.initializeTouchEvents(true)
var TouchClick = React.createClass({
defaults: {
touched: false,
touchdown: false,
coords: { x:0, y:0 },
evObj: {}
},
getInitialState: function() {
return this.defaults
},
handler: function() {
typeof this.props.handler == 'function' && this.props.handler.apply(this, arguments)
},
getCoords: function(e) {
if ( e.touches && e.touches.length ) {
var touch = e.touches[0]
return {
x: touch.pageX,
y: touch.pageY
}
}
},
onTouchStart: function(e) {
this.setState({
touched: true,
touchdown: true,
coords: this.getCoords(e),
evObj: e
})
},
onTouchMove: function(e) {
var coords = this.getCoords(e)
var distance = Math.max(
Math.abs(this.state.coords.x - coords.x),
Math.abs(this.state.coords.y - coords.y)
)
if ( distance > 6 )
this.setState({ touchdown: false })
},
onTouchEnd: function() {
if(this.state.touchdown)
this.handler.call(this, this.state.evObj)
setTimeout(function() {
if ( this.isMounted() )
this.setState(this.defaults)
}.bind(this), 4)
},
onClick: function() {
if ( this.state.touched )
return false
this.setState(this.defaults)
this.handler.apply(this, arguments)
},
render: function() {
var classNames = ['touchclick']
this.props.className && classNames.push(this.props.className)
this.state.touchdown && classNames.push('touchdown')
return React.DOM[this.props.nodeName || 'button']({
className: classNames.join(' '),
onTouchStart: this.onTouchStart,
onTouchMove: this.onTouchMove,
onTouchEnd: this.onTouchEnd,
onClick: this.onClick
}, this.props.children)
}
})
Just pass handler
prop as the callback and wrap your content inside. This also works for systems that has both touch and click events (like newer windows 8 laptops). Example:
<TouchClick handler={this.clickHandler} className='app'>
<h1>Hello world</h1>
</TouchClick>

- 1,689
- 13
- 13

- 106,495
- 44
- 176
- 212
-
1I mean, this is not a wham-bam-thank-you-maam type solution that instantly gets rid of the annoying click delay for everything on the page, is it? That's the point of Fastclick – Andy May 19 '15 at 04:08
I had issues using David`s method, so as an alternative to FastClick, I implemented a mixin using HammerJs for the event. A bit more code to setup the event, but works fine.
var HammerClickMixin = React.createClass({
componentWillMount: function() {
this.listeneres = [];
},
addTapEvent: function(element,callback) {
var mc = new Hammer.Manager(element);
mc.add(new Hammer.Tap({ event: 'doubletap', taps: 2 }));
mc.add(new Hammer.Tap({ event: 'tap', taps: 1 }));
mc.on('tap',callback);
this.listeneres.push(mc);
},
addDoubleTap : function(element,callback){
var mc = new Hammer.Manager(element);
mc.add(new Hammer.Tap({ event: 'doubletap', taps: 2 }));
mc.on('doubletap',callback);
this.listeneres.push(mc);
},
componentWillUnmount: function() {
for(var i= 0; i < this.listeneres.length; i++){
this.listeneres[i].destroy();
}
}
});
This can then be used as as followed:
var Component = React.createClass({
mixins: [HammerClickMixin],
componentDidMount: function () {
this.addTapEvent(this.refs.elementToClick.getDOMNode(),function(){
//Handle fast hammer tap!
});
},
render: function () {
return (
<div ref="elementToClick"/>
);
}
});

- 106
- 3
It seemed to be working fine in my Cordova app, but there is one significant problem I ran into.
When an element is clicked using React+FastClick, and the next rendered view contains a clickable element in the same position, a onTouchEnd event is also registered in the second element.
I ditched FastClick as I don't want to align my buttons to avoid unwanted behaviour, but I need something to replace it as the click delay feels pretty bad.

- 718
- 9
- 13
-
3I had similar problems, where a button would be clicked immediately, but then in some environments (android browsers) would be clicked again 300ms later. The tap event plugin used in [react touch libs](https://github.com/petehunt/react-touch-lib/tree/master/src/thirdparty) adds a nice onTouchTap callback but it doesn't work on non-touch inputs. Making a React event plugin might be the way to go though. I still haven't found the answer... – nicholas Jul 20 '14 at 14:33
-
Thanks for the info, in fact after ditching FastClick I'm still running into similar "tap registers two times" problems, albeit in different parts of the app than previously. Haven't found a solution yet either... – Pirkka Esko Jul 21 '14 at 18:51
-
@PirkkaEsko so FastClick wasn't the cause of the `onTouchEnd` issue you were seeing? – Andy Jun 04 '15 at 21:33
-
1Honestly I don't remember the details anymore, but my comment above would suggest that FastClick was not the root cause but could have something to do with them, as behaviour was altered (issues were happening in different part of the app after removing FastClick). – Pirkka Esko Jun 05 '15 at 13:09
-
1I found this behavior with both fastclick and react-tap-event-plugin. Still haven't found a good solution. – nicholas Jun 19 '15 at 20:38
You can also use react-fastclick
(https://github.com/JakeSidSmith/react-fastclick) from npm:
npm i react-fastclick --save
Using it you don't have to change any of your code and it works really nice! You only have to require it once.
require('react-fastclick');

- 3,630
- 12
- 45
- 68