Touch/pointer events test results
Some of the more interesting data points from running my various touch/pointer tests on a variety of devices/browsers. All tests carried out manually, trying to get the cleanest possible results (e.g. getting a “clean” tap without any finger movement). Most testing carried out against this simple event listener test.
Some of these results first appeared in my presentation Getting touchy - an introduction to touch and pointer events, but have since been retested and are now collated here for easier referencing.
See also Peter-Paul Koch’s “Touch table”, where he tests some further aspects beyond the scope of my tests.
Last updated 26 August 2020. See complete change history.
Contents
- Mobile/tablet touchscreen activation/tap event order
- Mobile/tablet touchscreen with assistive technology event order
- Mobile/tablet touch devices with paired keyboard/mouse event order
- Desktop with touchscreen event order
- Desktop with assistive technology event order
- Desktop with touchscreen and assistive technology event order
- Suppressing 300ms delay for touchscreen interactions
- “Faked” event coordinates
Mobile/tablet touchscreen activation/tap event order
Browser | 1st tap | 2nd tap | Tap out |
---|---|---|---|
Firefox OS 1.1 | touchstart > (touchmove )+ > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
iOS 7.1 / Safari/WebView | touchstart > (touchmove )+ > touchend > (mouseenter) > mouseover > mousemove > mousedown > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseleave > mouseout (when tapping to another focusable/activatable element, otherwise none due to iOS’s event delegation/bubbling idiosyncrasy) |
Opera Mini 8 / iOS 7.1.1 (Mini mode, Turbo and Wi-Fi consistent with Safari/iOS) | mouseover > mousemove > mousedown > mouseup > click |
mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur (when tapping to another focusable/activatable element, otherwise none ) |
Android 2.1 (HTC Hero) / “Internet” (WebKit 530.17) | touchstart > (touchmove )+ > touchend > mouseover > mousemove > mousedown > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout |
Android 2.3.7 / Browser (WebKit 533.1) | touchstart > (touchmove )+ > touchend > mouseover > mousemove > mousedown > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout |
Android 4.3 / Chrome M34 | touchstart > (touchmove )+ > touchend > mouseover > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > blur |
Android 4.3 / Miren Browser, Maxthon Browser, Dolphin Browser (HD), Browser (WebKit 534.30) | mouseover > mousemove > touchstart > (touchmove )+ > touchend > mousedown > mouseup > click |
mousemove > touchstart > (touchmove )+ > touchend > mousedown > mouseup > click |
mouseout |
Android 6 / Dolphin Browser 11.5 | mouseover > mousemove > touchstart > (touchmove )+ > touchend > mousedown > mouseup > click |
mousemove > touchstart > (touchmove )+ > touchend > mousedown > mouseup > click |
mouseout |
Android 4.3 / UC Browser 9.6 (WebKit 533.1) | mouseover > mousemove > touchstart > (touchmove )+ > touchend > mousedown > focus > mouseup > click |
mousemove > touchstart > (touchmove )+ > touchend > mousedown > mouseup > click |
mouseout > blur |
Android 6 / UC Browser 10.8 | mouseover > mousemove > touchstart > (touchmove )+ > touchend > mousedown > focus > mouseup > click |
mousemove > touchstart > (touchmove )+ > touchend > mousedown > mouseup > click |
mouseout > blur |
Android 4.3 / Opera 19 (Blink) | touchstart > (touchmove )+ > touchend > mouseover > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > blur |
Android 4.3 / Opera Classic | touchstart > (touchmove )+ > touchend > mouseenter > mouseover > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 4.3 / Firefox 28 | touchstart > (touchmove )+ > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 4.3 / Puffin 4.0.1.828 (no touch event support) | mouseenter > mouseover > mousemove > mousedown > focus > mouseup > click |
mousemove > mousedown > mouseup > click |
mouseleave > mouseout > blur |
Android 4.4 / Maxthon Browser HD 4.0.4.1000 | touchstart > touchend > mouseover > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout > blur |
BlackBerry PlayBook 2.0 (2.1.0.1917) / Browser (WebKit 536.2) | touchstart > mouseover > mousemove > mousedown > touchend > mouseup > click |
touchstart > mousemove > mousedown > touchend > mouseup > click |
mouseout |
Blackberry (BBOS 10.1) / Browser | touchstart > touchend > mouseover > mousemove > mousedown > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout |
Windows Phone 8 / IE10 (pointer events, vendor-prefixed) | mousemove > MSPointerOver > mouseover > mouseenter > MSPointerDown > mousedown > (MSGotPointerCapture ) > focus (if previously focus was somewhere else on page) > MSPointerUp > mouseup > (MSLostPointerCapture ) > MSPointerOut > mouseout > mouseleave > focus (if nothing previously focused on page) > click if moving finger slightly during press: mousemove > MSPointerOver > mouseover > mouseenter > MSPointerDown > mousedown > (MSGotPointerCapture ) > focus > (MSPointerMove > mousemove )+ > MSPointerUp > mouseup > click > (MSLostPointerCapture ) > MSPointerOut > mouseout > mouseleave |
mousemove > MSPointerOver > mouseover > mouseenter > MSPointerDown > mousedown > (MSGotPointerCapture ) > MSPointerUp > mouseup > (MSLostPointerCapture ) > MSPointerOut > mouseout > mouseleave > click if moving finger slightly during press: mousemove > MSPointerOver > mouseover > mouseenter > MSPointerDown > mousedown > (MSGotPointerCapture ) > (MSPointerMove > mousemove )+ > MSPointerUp > mouseup > click > (MSLostPointerCapture ) > MSPointerOut > mouseout > mouseleave |
blur |
Windows Phone 8.1 / IE11 (pointer events) | mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > (pointermove > mousemove )+ > pointerup > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > focus > click if moving finger slightly during press: mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > pointermove > mousemove > focus > (pointermove > mousemove )+ > pointerup > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > click |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > (pointermove > mousemove )+ > pointerup > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > click unable to replicate a tap with slight movement which does not result in a pointercancel |
blur |
Windows Phone 8.1 Update 1 / IE11 (pointer events + touch events) | mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > touchstart > mousedown > (gotpointercapture ) > focus > pointermove > mousemove > pointerup > touchend > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > click if moving finger slightly during press: mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > touchstart > mousedown > (gotpointercapture ) > focus > pointermove > mousemove > (pointermove > touchmove > mousemove )+ > pointerup > touchend > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > click (slightly erratic - sometimes only fires pointermove > mousemove without touchmove , sometimes just pointermove > mousemove followed by full pointermove > touchmove > mousemove ) |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > touchstart > mousedown > (gotpointercapture ) > pointermove > mousemove > pointerup > touchend > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > click if moving finger slightly during press: mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > tochstart > mousedown > (gotpointercapture ) > (pointermove > touchmove > mousemove )+ > pointerup > touchend > mouseup > click > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave (slightly erratic - sometimes only fires pointermove > mousemove without touchmove , sometimes just pointermove > mousemove followed by full pointermove > touchmove > mousemove ) |
blur |
Windows 10 Mobile Technical Preview (OS version 10.0.12534.59) / Spartan (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click > (lostpointercapture ) > pointerout > pointerleave (note all mouse events fired after touchend - also focus and lostpointercapture currently happen differently than on desktop with touch) |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > touchend > mousemove > mousedown > mouseup > click > (lostpointercapture ) > pointerout > pointerleave (note all mouse events fired after touchend - also focus and lostpointercapture currently happen differently than on desktop with touch) |
mouseout > mouseleave (note no blur , even when tapping away to another focusable element) |
Windows 10 Mobile / Microsoft Edge 11 (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click > (lostpointercapture ) > pointerout > pointerleave (note all mouse events fired after touchend - also focus and lostpointercapture currently happen differently than on desktop with touch) |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > touchend > mousemove > mousedown > mouseup > click > (lostpointercapture ) > pointerout > pointerleave (note all mouse events fired after touchend - also focus and lostpointercapture currently happen differently than on desktop with touch) |
mouseout > mouseleave > blur |
Windows 10 Mobile / Microsoft Edge 21.10549 (pointer events + touch events) | mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > touchstart > mousedown > (gotpointercapture ) > focus > pointermove > mousemove > pointerup > touchend > mouseup > click > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave (same as desktop with touchscreen, barring the faked touch events which are disabled on desktop) |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > touchstart > mousedown > (gotpointercapture ) > pointermove > mousemove > pointerup > touchend > mouseup > click > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave (same as desktop with touchscreen, barring the faked touch events which are disabled on desktop) |
blur |
Android 6.0.1 / Chrome 53 (Dev) (pointer events experimental support + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > pointerout > pointerleave > (lostpointercapture ) > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > pointerout > pointerleave > (lostpointercapture ) > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Chrome 56 (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Samsung Internet for Android 4.0.20-6 | touchstart > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Windows 10 Mobile / Microsoft Edge 25.10586.107.0 (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointermove > pointerup > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click > lostpointercapture > pointerout > pointerleave |
pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointermove > pointerup > touchend > mousemove > mousedown > mouseup > click > lostpointercapture > pointerout > pointerleave |
mouseout > mouseleave > blur |
Amazon Fire OS 5.3.3.0 (Android 5.1.1) / Silk Browser 58.2.6.3029.83.10 (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
iOS 12.2 / Safari/WebView | touchstart > (touchmove )+ > touchend > mouseover > mouseenter > mousemove > mousedown > mouseup > click > mousedown > mouseup > click (note the odd double firing of events at the end) |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave (when tapping to another focusable/activatable element, otherwise none due to iOS’s event delegation/bubbling idiosyncrasy) |
iOS 12.2 / Safari (Experimental WebKit Features - Pointer Events) | pointerdown > touchstart > pointermove > pointerup > touchend > pointerup > mouseover > mouseenter > mousemove > mousedown > mouseup > click > mousedown > mouseup > click (note the odd double firing of events at the end) |
pointerdown > touchstart > pointerup > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave (when tapping to another focusable/activatable element) |
Android 6.0.1 / Chrome 74 (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Firefox 66.0.2 | touchstart > (touchmove )+ > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Firefox 68.0a1 (Nightly) | pointerover > pointerenter > pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 10 / Chrome 77 (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > (pointermove )+ > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > (pointermove )+ > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 10 / Firefox 68.1.1 (with Pointer Events enabled explicitly in about:config ) |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
iOS 13.1 / Safari (pointer events + touch events) | pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointermove > pointermove > pointerup > lostpointercapture > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointermove > pointermove > pointerup > lostpointercapture > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave (when tapping to another focusable/activatable element) |
Generally, only a single (“sacrificial”) mousemove
is fired as part of the mouse compatibility events, just to rattle any legacy scripts that may be listening for this event.
There is a bug in WebKit (affecting iOS 7.1/Safari and WebView) where mouseenter
mouse compatibility event is not being fired correctly - see Bug 128534 - . This has been fixed in iOS 8mouseenter
mouse compat event not fired when listeners for touch events
In the touch event model, mouse compatibility events (and final click
) are only fired when a single finger is on the touchscreen. As soon as there’s two or more (even outside of the element we’re listening on), only touch events are fired and mouse compatibility events are suppressed (or, in certain browsers like default Android “Browser”, no events are fired at all unless all touches happen on the element with the listener - if, for instance, one finger is touching the screen outside of the element, a tap with a second finger will generate no events at all).
There is a bug in current Blink implementations (noticed in Android/Chrome M34, M35 beta, and related Blink-based browsers like Opera) which also suppresses actual touch events if the first touch happened on a region with no touch handlers - see Issue 363321: No touch are ever events fired if the first finger went down in an area with no handler.
If during the tap there is too much movement of the finger (based on browser-specific threshold), this is considered a gesture rather than a tap, and any mouse compatibility events (including click
) are generally not fired.
There is a bug in older versions of Blink and Webkit (noticed in Android/Chrome M34, Android/Opera, Android/Maxthon, Android/Browser) where even the slightest movement during a tap results in touchstart
, a single touchmove
only, and a touchcancel
, with no further events being dispatched. This behavior is inconsistent with other implementations (as noted above, the result is usually touchstart
, a few touchmove
events, a touchend
and then - provided the movement was within the threshold - the mouse compatibility and click
events). Android/Chrome M35 (beta) seems to have fixed this bug - see Issue 363319: Swiping over a button with touch event handlers results in a single touchmove then touchcancel.
When testing touch events on desktop using developer tools emulation, note there are currently bugs in the order/type of events being fired:
- Chrome:
Issue 181204: Emulate touch events - event order different from real devices - Firefox:
Bug 920956 - DevTools touch emulation: suppress regular mouse events, emulate 300ms delay
Note the mix of pointer and touch events in Windows Phone 8.1 Update 1 - see MSDN: The Mobile Web should just work for everyone.
Note that Spartan on current Windows 10 Mobile Technical Preview behaves subtly differently from Spartan on Windows 10 Technical Preview on desktop with touchscreen.
There is some oddity/bug in iOS 12.2, with mousedown
, mouseup
and click
being fired twice when first tapping on the control. The experimental WebKit feature for pointer events also generates some duplicate pointerup
events.
For Android, most Chromium-based browsers (Edge, Samsung Internet, Brave) now behave consistently with Chrome.
Mobile/tablet touchscreen with assistive technology event order
Using touch gestures (e.g. swipe left/right, double-tap to activate) and “touch explore”.
Browser | Move to button | 1st activation | 2nd activation | Leave button |
---|---|---|---|---|
iOS 7.1 / Safari/WebView + VoiceOver (with and without keyboard, and using “touch explore”) | focus |
touchstart > touchend > mouseenter > mouseover > mousemove > mousedown > blur > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
blur (when moving to another focusable element without activating the control first, otherwise none )mouseleave > mouseout (fired after element was already left, if original element was activated, and now another element was activated) |
iOS 9.2 / Safari/WebView + VoiceOver (with and without keyboard, and using “touch explore”) | focus |
touchstart > touchend > *mouseover* > mouseenter > mousemove > mousedown > blur > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
blur (when moving to another focusable element without activating the control first, otherwise none )*mouseout* > mouseleave (fired after element was already left, if original element was activated, and now another element was activated) |
Android 4.3 / Chrome M34 + TalkBack (effectively ChromeVox, same behavior in other WebView/WebKit enabled browsers like Miren, Maxthon, etc) | focus mouseenter > mouseover > (mousemove )+ > focus (when using “touch explore”) |
blur > mousedown > mouseup > click > focus |
blur > mousedown > mouseup > click > focus |
blur ( mousemove )+ > mouseleave > mouseout (when using “touch expore”) |
Android 6.0.1 / Chrome 47 + TalkBack | none |
touchstart > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur (after moving to and activating another focusable element) |
Android 4.3 / Firefox 28 + TalkBack | none mousover (when using “touch explore”) |
touchstart > mousedown > focus > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur (only if element was activated at least once, and only when moving to another focusable element and activating it, otherwise none )mouseout > blur (when using “touch explore” - blur also only fired if element was activated at least once, and only when moving to another focusable element and activating it) |
Android 6.0.1 / Firefox 47 + TalkBack | none mousover > mouseenter > (mousemove )+(when using “touch explore”) |
touchstart > mousedown > focus > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur (only if element was activated at least once, and only when moving to another focusable element and activating it, otherwise none )mouseout > mouseleave blur (when using “touch explore” - blur also only fired if element was activated at least once, and only when moving to another focusable element and activating it) |
Blackberry (BBOS10) / Browser + Screen Reader | none |
touchstart > touchend > mouseover > mousemove > mousedown > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout (after moving to and activating another focusable element) |
Windows Phone 8.1 / IE11 + Narrator | none |
focus > click |
click |
blur (after moving and activating another focusable element) |
Windows Phone 8.1 Update 1 / IE11 + Narrator | none |
focus > click |
click |
blur (after moving and activating another focusable element) |
Windows 10 Mobile / Microsoft Edge 21.10549 + Narrator (without keyboard) | none |
focus > click |
click |
blur (after moving and activating another focusable element) |
Android 6.0.1 / Chrome 53 (Dev) + TalkBack (pointer events experimental support + touch events) | none |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > pointerout > pointerleave > (lostpointercapture ) > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > pointerout > pointerleave > (lostpointercapture ) > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur (after moving and double-tapping another element) |
Android 6.0.1 / Chrome 56 + TalkBack (pointer events + touch events) | none |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Samsung Internet for Android 4.0.20-6 + TalkBack | none |
touchstart > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur (after moving to and activating another focusable element) |
Windows 10 Mobile / Microsoft Edge 25.10586.107.0 + Narrator (without keyboard) | none |
focus > click |
click |
none (even after moving and activating another focusable element - however, returning to the button and activating it does fire focus again, so the focus is moved from it, just not reported/blur not fired) |
iOS 12.2 / Safari/WebView + VoiceOver (with and without keyboard, and using “touch explore”) | none |
touchstart > touchend > mouseover > mouseenter > mousemove > mousedown > mouseup > click > mousedown > mouseup > click (note the odd double firing of events at the end) |
touchstart > touchend > mousemove > mousedown > mouseup > click |
none (even after moving and activating another focusable element) |
iOS 12.2 / Safari (Experimental WebKit Features - Pointer Events) + VoiceOver (with and without keyboard, and using “touch explore”) | none |
pointerdown > touchstart > pointerup > touchend > mouseover > mouseenter > mousemove > mousedown > mouseup > click > mousedown > mouseup > click (note the odd double firing of events at the end) |
pointerdown > touchstart > pointerup > touchend > mousemove > mousedown > mouseup > click |
none (even after moving and activating another focusable element) |
Android 6.0.1 / Chrome 74 + TalkBack | none |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Chrome 74 + TalkBack + keyboard | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (but only when activating certain other controls, not consistently?) |
Android 6.0.1 / Firefox 66.0.2 + TalkBack | none |
touchstart > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
blur |
Android 6.0.1 / Firefox 66.0.2 + TalkBack + Keyboard | none |
touchstart > mousedown > focus > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur |
Android 6.0.1 / Firefox 68.0a1 (Nightly) + TalkBack | none |
pointerover > pointerenter > pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Firefox 68.0a1 (Nightly) + TalkBack + Keyboard | none |
touchstart > mousedown > focus > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur (after activating another control) |
Android 10 / Chrome 77 + TalkBack | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (but only when activating certain other controls, not consistently?) |
Android 10 / Chrome 77 + TalkBack + keyboard | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (but only when activating certain other controls, not consistently?) |
Android 10 / Firefox 68.1.1 (with Pointer Events explicitly enabled in about:config ) + TalkBack |
none |
touchstart > mousedown > focus > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur (after activating another control) |
Android 10 / Firefox 68.1.1 (with Pointer Events explicitly enabled in about:config ) + TalkBack + keyboard |
none |
touchstart > mousedown > focus > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur (after activating another control) |
iOS 13.1 / Safari + VoiceOver (with and without keyboard, and using “touch explore”) | none |
pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointerup > lostpointercapture > pointerout > pointerleave > touchend > focus > mousedown > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointerup > lostpointercapture > pointerout > pointerleave > touchend > mousedown > mouseup > click |
none (even after moving and activating another focusable element) |
No assistive technology available (yet) for Firefox OS, Windows Phone 8 or BlackBerry PlayBook.
Moving the focus (swiping left/right and using “touch explore”) won’t always fire a JavaScript focus
event – in many cases, focus
is only sent as part of the series of events that follow an activation (double-tap). Though perhaps not a problem in practice, it can cause problems for widgets that expect focus (e.g. skip links that are visually hidden initially) - see Bug 1000082 - [AccessFu] When virtual focus is on a button or link, fire actual focus on the element, too, Issue 657157 - Issue with skip links that are visible only on focus.
Mobile/tablet screenreaders are quite liberal in firing additional blur
events when an element is activated – presumably in an attempt to prevent focus-specific CSS styles to “stick” after a user tapped on an in-page link or control. Careful if your code assumes blur
means the user has moved away from the focusable element, as the AT focus is actually still there.
There are dramatic differences in the events being fired between gesture navigation and “touch explore” on Android.
There is a bug in WebKit (affecting iOS 7.1/Safari and WebView) where mouseenter
mouse compatibility event is not being fired correctly - see Bug 128534 - (fixed in iOS 8).mouseenter
mouse compat event not fired when listeners for touch events
Currently in Microsoft Edge 21.10549 it is not possible to use Narrator together with a paired keyboard on a Windows 10 Mobile device to navigate the actual web content – it seems the web view itself is not exposed correctly when using TAB / SHIFT+TAB.
There is some oddity/bug in iOS 12.2, with mousedown
, mouseup
and click
being fired twice when first tapping on the control.
First noticed in iOS 12.2 (but likely happened some time ago): focus
is now not fired anymore when the button receives VO focus. likewise, leaving the button and activating some other control does not fire any events anymore either. Compare to old iOS 7.1 behaviour.
For Android, latest testing (April 2019) used more appropriate keyboard interaction (ALT+SHIFT plus cursor keys / ENTER to move focus/trigger control) - previous testing may have been limited to just TAB / SHIFT+TAB). Note how both Chrome and Firefox still send different event sequence if TalkBack is operated using gestures and keyboard.
For Android, most Chromium-based browsers (Edge, Samsung Internet, Brave) now behave consistently with Chrome.
Mobile/tablet touch devices with paired keyboard/mouse event order
Browser | Move to button | 1st activation | 2nd activation | Leave button |
---|---|---|---|---|
Android 2.1 (HTC Hero) + built-in trackball / “Internet” (WebKit 530.17) | mouseover > mousemove |
mousemove > mousedown > mouseup > click |
mousemove > mousedown > mouseup > click |
mouseout (when moving to another focusable element, otherwise none ) |
Android 2.3.7 / Browser + mouse | none |
touchstart > touchend > mouseover > mousemove > mousedown > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout (when clicking somewhere else) |
Android 2.3.7 / Firefox 28 + mouse | none |
touchstart > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur (when clicking somewhere else) |
Android 2.3.7 / Opera 12 + mouse | none |
touchstart > touchend > mouseover > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend mousedown > mouseup > click |
mouseout > mouseleave > blur (when clicking somewhere else) |
Android 4.3 / Browser + mouse | mouseover > (mousemove )+ |
(mousemove )+ > touchstart > touchend > (mousemove )+ > mousedown > mouseup > click |
(mousemove )+ > touchstart > touchend > (mousemove )+ > mousedown > mouseup > click |
(mousemove )+ > mouseout |
Android 4.3 / Chrome M34 + mouse | mouseenter > mouseover > (mousemove )+ |
mouseleave > mouseout > touchstart > touchend > mouseenter > mouseover > (mousemove )+ > mousedown > focus > mouseup > click > mousemove |
mouseleave > mouseout > touchstart > touchend > mouseenter > mouseover > (mousemove )+ > mousedown > mouseup > click > mousemove |
(mousemove )+ > mouseleave > mouseout |
Android 4.3 / Chrome M34 + keyboard | focus |
click |
click |
blur |
Android 6 / Chrome + mouse | mouseover > mouseenter > (mousemove )+ |
mouseout > mouseleave > touchstart > touchend > mouseover > mouseenter > (mousemove )+ > mousedown > focus > mouseup > click > mousemove |
mouseout > mouseleave > touchstart > touchend > mouseover > mouseenter > (mousemove )+ > mousedown > mouseup > click > mousemove |
(mousemove )+ > mouseout > mouseleave |
Android 6 / Chrome + keyboard | focus |
click |
click |
blur |
Android 4.3 / Opera 19 (Blink) + keyboard (no focus indication) | focus |
click |
click |
blur |
Android 4.3 / Firefox 28 + mouse | mouseover > mouseenter > (mousemove )+ |
mouseleave > touchstart > touchend > mouseenter > (mousemove )+ > mousedown > focus > mouseup > click |
mouseleave > touchstart > touchend > mouseenter > (mousemove )+ > mousedown > mouseup > click > mousemove |
(mousemove )+ > mouseout > mouseleave |
Android 4.3 / Firefox 28 + keyboard | focus |
click |
click |
blur |
Android 6 / Firefox 44 + mouse | mouseover > mouseenter > (mousemove )+ |
touchstart > touchend > (mousemove )+ > mousedown > focus > mouseup > click > mousemove |
touchstart > touchend > (mousemove )+ > mousedown > mouseup > click > mousemove |
(mousemove )+ > mouseout > mouseleave |
Android 6 / Firefox 44 + keyboard | focus |
click |
click |
blur |
BlackBerry PlayBook 2.0 (2.1.0.1917) / Browser (WebKit 536.2) + mouse | mouseover > (mousemove )+ |
mousedown > mouseup > click |
mousedown > mouseup > click |
(mousemove )+ > mouseout |
BlackBerry PlayBook 2.0 (2.1.0.1917) / Browser (WebKit 536.2) + keyboard | focus |
click |
click |
blur |
Blackberry (BBOS 10) / Browser + mouse | mouseover > (mousemove )+ |
mousedown > mouseup > click |
mousedown > mouseup > click |
(mousemove )+ > mouseout |
Blackberry (BBOS 10) / Browser + keyboard | focus |
click |
click |
blur |
Windows 10 Mobile / Microsoft Edge + mouse | pointermove > mousemove > pointerover > mouseover > pointerenter > mouseenter > (pointermove > mousemove )+ |
pointerdown > mousedown > focus > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
pointerout > mouseout > pointerleave > mouseleave |
Windows 10 Mobile / Microsoft Edge + keyboard | focus |
click |
click |
blur |
Android 6.0.1 / Chrome 53 (Dev) + keyboard | focus |
click |
click |
blur |
Android 6.0.1 / Chrome 53 (Dev) + mouse (pointer events experimental support + touch events) | pointerover > pointerenter > mouseover > mouseenter |
pointerout > pointerleave > mouseout > mouseleave > pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture) > pointerup > pointerout > pointerleave > (lostpointercapture) > touchend > pointerover > pointerenter > mouseover > mouseenter > pointermove > mousemove > mousedown > focus > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave > pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture) > pointerup > pointerout > pointerleave > (lostpointercapture) > touchend > pointerover > pointerenter > mouseover > mouseenter > pointermove > mousemove > mousedown > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave > blur |
Android 6.0.1 / Chrome 56 + keyboard | focus |
click |
click |
blur |
Android 6.0.1 / Chrome 56 + mouse (pointer events + touch events) | none |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Samsung Internet for Android 4.0.20-6 + keyboard | focus |
click |
click |
blur |
Android 6.0.1 (on Samsung Note) / Samsung Internet for Android 4.0.20-6 + mouse | mouseover > mouseenter > (mousemove )+ |
mousemove > touchstart > touchend > (mousemove)+ > mousedown > focus > mouseup > click |
mousemove > touchstart > touchend > (mousemove )+ > mousedown > mouseup > click |
(mousemove )+ > mouseout > mouseleave |
Android 6.0.1 (on Google Nexus) / Samsung Internet for Android 5.4 (Beta) + mouse | none |
touchstart > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
touchstart > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Android 6.0.1 / Chrome 59 + mouse (since Chrome 58, new mouse handling, does not mimic touch) | none |
pointerover > pointerenter > mouseover > mouseenter > pointerdown > mousedown > focus > pointermove > mousemove > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave > blur |
iOS 12.2 / Safari/WebView + keyboard (without and with Experimental WebKit Features - Pointer Events) | focus |
click |
click |
blur |
Android 6.0.1 / Chrome 74 + mouse | none |
pointerover > pointerenter > mouseover > mouseenter > pointerdown > mousedown > focus > (pointermove > mousemove >) pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave > blur (when clicking away on the page/another element) |
Android 6.0.1 / Firefox 66.0.2 + mouse | mouseover > mouseenter > (mousemove )+ |
touchstart > touchend > (mousemove )+ > mousedown > focus > mouseup > click |
touchstart > touchend > (mousemove )+ > mousedown > mouseup > click |
(mousemove )+ > mouseout > mouseleave (when moving the mouse out of the button)blur (when clicking away on the page/another element) |
Android 6.0.1 / Firefox 68.0a1 + mouse | pointerover > pointerenter > pointermove > mouseover > mouseenter > mousemove (> pointermove > mousemove )+ |
pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > pointerover > pointerenter > pointermove > mousemove > mousedown > focus > mouseup > click |
pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > pointerover > pointerenter > pointermove > mousemove > mousedown > focus > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave > blur (when clicking away on the page/another element) |
Android 10 / Chrome 77 + keyboard | focus |
click |
click |
blur |
Android 10 / Firefox 68.1.1 + keyboard | focus |
click |
click |
blur |
Android 10 / Chrome 77 + mouse | none |
pointerover > pointerenter > mouseover > mouseenter > pointerdown > mousedown > focus > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave > blur (after clicking outside of the button) |
Android 10 / Firefox 68.1.1 (with Pointer Events enabled in about:config ) + mouse |
pointerover > pointerenter > pointermove > mouseover > mouseenter > mousemove |
pointerdown > touchstart > (gotpointercapture) > pointerup > (lostpointercapture) > pointerout > pointerleave > touchend > pointerover > pointerenter > pointermove > mousemove > mousedown > focus > mouseup > click |
pointerdown > touchstart > (gotpointercapture) > pointerup > (lostpointercapture) > pointerout > pointerleave > touchend > pointerover > pointerenter > pointermove > mousemove > mousedown > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave (after clicking somehwere else, blur ) |
Android 10 / Firefox Preview 4.3.0 / 38.0.0 + mouse | pointerover > pointerenter > pointermove > mouseover > mouseenter > mousemove |
pointerdown > mousedown > focus > pointerup > mouseup > click > pointermove > mousemove |
pointerdown > mousedown > pointerup > mouseup > click > pointermove > mousemove |
pointerout > pointerleave > mouseout > mouseleave |
Android 10 / Puffin 7.8.3 + mouse | pointerover > pointerenter > mouseover > mouseenter |
pointerdown > mousedown > focus > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave (after clicking somehwere else, blur ) |
iOS 13.1 / Safari/WebView + keyboard | focus |
click |
click |
blur |
iOS 13.1 / Safari/WebView + mouse | none |
pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointermove > pointermove > pointerup > lostpointercapture > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > gotpointercapture > pointermove > pointermove > pointerup > lostpointercapture > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave (when clicking on another focusable/activatable element) |
iOS 13.6 / Safari/WebView + keyboard with “Full Keyboard Access” enabled |
focus |
pointerover > pointerenter > pointerdown > touchstart > pointerover > mouseover > pointerenter > mouseenter > gotpointercapture > pointerup > lostpointercapture > pointerout > mouseout > pointerleave > mouseleave > pointerout > pointerleave > touchend > mousedown > mouseup > click |
pointerove > pointerenter > pointerdown > touchstart > pointerover > mouseover > pointerenter > mouseenter > gotpointercapture > pointerup > lostpointercapture > pointerout > mouseout > pointerleave > mouseleave > pointerout > pointerleave > touchend > mousedown > mouseup > click |
blur |
iPadOS 13.4 / Safari/WebView + mouse | pointerover > mouseover > pointerenter > mouseenter |
pointerdown > mousedown > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
pointerout > mouseout > pointerleave > mouseleave |
Firefox OS (ZTE Open) currently does not support paired bluetooth mouse/keyboard.
Android 2.3.7 only has partial keyboard support. It was not possible to successfully pair a keyboard or mouse with the Android 2.1 HTC Hero test device.
Windows Phone 8 (Nokia Lumia 520) does not support paired bluetooth mouse/keyboard.
Windows 10 Mobile does support paired bluetooth mouse and keyboard - with a mouse, Microsoft Edge behaves exactly the same as Win8.1/IE11 or Windows 10/Microsoft Edge, firing the same events and no faked touch events (even though it does support both touch and pointer events). However, it is not possible to use to keyboard to navigate - using TAB / SHIFT+TAB has no effect. Using a paired keyboard, Microsoft Edge also behaves the same way as its desktop counterpart, only firing focus
, click
and blur
events.
In Android/Chrome 53 (Dev), note how the browser (which supports both touch and pointer events) when paired with a mouse attempts to keep “closure” of the mouse pointer by continuously adding/removing the pointer (firing extra sets of pointerover
/ pointerenter
/ pointerout
/ pointerleave
and related compatibility mouse events), compared to Windows 10 Mobile with mouse.
From Android/Chrome 58 onwards, mouse handling behaves like on desktop, and does not mimic touch anymore.
In Firefox 68.0a1 (Nightly), notice the odd pointerout
, pointerleave
followed milliseconds later by pointerover
, pointerenter
- like during each tap/activation, the mouse is completely removed from over the element and then reappears.
On Android + mouse, note how Chromium-based browsers all don’t fire any events when mouse pointer is moved over the button (compared to desktop); Firefox and Puffin seem the only main browsers that behave like desktop here (though some of the event sequences are quirky).
For Android, most Chromium-based browsers (Edge, Samsung Internet, Brave) now behave consistently with Chrome.
iOS does not support paired mouse, paired keyboard only works in same situations as on-screen keyboard (e.g. when prompted to enter a web address, enter data in a text input) unless VoiceOver is also activated (in which case it supports full control, but acts the same as regular VoiceOver with touch gestures).
iOS 12.2 (and probably some earlier versions) now supports partial keyboard support even without VoiceOver - navigate using Option+TAB / Option+SHIFT+TAB, activate links and buttons using ENTER (but SPACE doesn’t seem to work for buttons/controls).
iOS 13 introduced support for mouse, but only as a pointing device for Accessibility > Touch > AssistiveTouch. Once paired, the mouse displays a cursor, but acts exactly like touch - it does not hover, or fire any mouseover
/mouseenter
/mouseleave
mouseout
(or pointer events equivalent) events. In the pointer events it does fire (on clicking the mouse button), it identifes as a type=="touch"
pointer.
iPadOS 13.4 introduced full support for mouse. It now correctly behaves exactly like a desktop mouse. However, it seems to get confused when a mouse “suddenly appears” (e.g. when navigating via touch, and then simply clicking a mouse button that was previously positioned somehwere like a button … it then sends a bizarre combination of touch, pointer and mouse events).
iOS 13.6 (possibly earlier) has an additional setting under “Accessibility > Keyboards” to enable “Full Keyboard Access”. When this is enabled, it is possible to navigate through apps and content (including web content) in a way that’s comparable to desktop keyboard access. Note though that, as noted in the table, the event sequence that is fired includes Pointer Events, Touch Events, and fallback mouse events, rather than just classic keyboard events. This is presumably done as a backwards-compatibility measure to ensure that content that makes assumptions (“it’s a mobile/iPhone, so don’t need to listen to keyboard events…”) still works.
Android 10 / Firefox 68 has some oddities relating to mouse support - see https://bugzilla.mozilla.org/show_bug.cgi?id=1629353. These have been eliminated in the more recent Firefox Preview builds, which use different mouse handling on Android.
Android 10 / Chrome also still does not fully handle mouse hovering - see https://bugs.chromium.org/p/chromium/issues/detail?id=1028118
Desktop with touchscreen event order
Browser | 1st tap | 2nd tap | Tap out |
---|---|---|---|
Windows 8 / Chrome 33 (supports touch events) | touchstart > (touchmove )+ > touchend > mouseover > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > blur |
Windows 8 / Firefox 28 | mouseover > mouseenter > mousemove > mousedown > focus > (mousemove )+ > mouseup > click |
mousemove > mousedown > (mousemove )+ > mouseup > click |
mouseout > mouseleave > blur |
Windows 8 / Opera 12 (Presto) | mouseover > mousemove > mousedown > focus > mouseup > click |
mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Windows 8 / Opera 20 (Blink) (supports touch events) | touchstart > (touchmove )+ > touchend > mouseover > mousemove > mousedown > focus > mouseup > click |
touchstart > (touchmove )+ > touchend > mousemove > mousedown > mouseup > click |
mouseout > blur |
Windows 8 / IE11 (supports pointer events) | mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > focus > pointermove > mousemove > pointerup > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > click (note click at the end, which is not per Pointer Events specification) |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > pointermove > mousemove > pointerup > mouseup > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave > click (note click at the end, which is not per Pointer Events specification) |
blur |
Windows 10 Pro Technical Preview (build 10041) / IE (Edge) Touch Events disabled, Interop Mouse Events for Touch disabled |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > focus > (gotpointercapture ) > pointermove > mousemove > pointerup > mouseup > (lostpointercapture ) > click > pointerout > mouseout > pointerleave > mouseleave (note click in correct sequence as per Pointer Events specification, and focus now before gotpointercapture ) |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > pointermove > mousemove > pointerup > mouseup > (lostpointercapture ) > click > pointerout > mouseout > pointerleave > mouseleave (note click in correct sequence as per Pointer Events specification, and focus now before gotpointercapture ) |
blur |
Windows 10 Pro Technical Preview (build 10041) / IE (Edge) Touch Events enabled, Interop Mouse Events for Touch disabled |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > touchstart > mousedown > focus > (gotpointercapture ) > pointermove > touchmove > mousemove > pointerup > touchend > mouseup > (lostpointercapture ) > click > pointerout > mouseout > pointerleave > mouseleave (note touchstart and touchend ) |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > touchstart > mousedown > (gotpointercapture ) > pointermove > touchmove > mousemove > pointerup > touchend > mouseup > (lostpointercapture ) > click > pointerout > mouseout > pointerleave > mouseleave (note touchstart and touchend ) |
blur |
Windows 10 Pro Technical Preview (build 10041) / IE (Edge) Touch Events enabled, Interop Mouse Events for Touch enabled |
pointerover > pointerenter > pointerdown > touchstart > focus > (gotpointercapture ) > pointermove > pointerup > touchend > (lostpointercapture ) > mouseover > mouseenter > mousemove > mousedown > mouseup > click > pointerout > pointerleave (note all mouse events fired after touchend ) |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > touchend > (lostpointercapture ) > mousemove > mousedown > mouseup > click > pointerout > pointerleave (note all mouse events fired after touchend ) |
blur |
Windows 10 Pro Technical Preview (build 10049) / Spartan (same as IE (Edge) with Touch Events enabled, Interop Mouse Events for Touch enabled) |
pointerover > pointerenter > pointerdown > touchstart > focus > (gotpointercapture ) > pointermove > pointerup > touchend > (lostpointercapture ) > mouseover > mouseenter > mousemove > mousedown > mouseup > click > pointerout > pointerleave (note all mouse events fired after touchend ) |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > touchend > (lostpointercapture ) > mousemove > mousedown > mouseup > click > pointerout > pointerleave (note all mouse events fired after touchend ) |
blur |
Windows 10 / Microsoft Edge (by default touch events and mouse events for touchdisabled) |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > focus > (gotpointercapture ) > pointermove > mousemove > pointerup > mouseup > (lostpointercapture ) > click > pointerout > mouseout > pointerleave > mouseleave |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > pointermove > mousemove > pointerup > mouseup > (lostpointercapture ) > click > pointerout > mouseout > pointerleave > mouseleave |
blur |
Windows 10 / Chrome 53 (Dev) (pointer events experimental support + touch events) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > pointerout > pointerleave > (lostpointercapture ) > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > pointerout > pointerleave > (lostpointercapture ) > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Chromebook Pixel / Chrome OS 69.0.3497.120 | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Windows 10 / Chrome 77 | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointermove > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Windows 10 / Firefox 69 | pointerover > pointerenter > pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > pointerup > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
Windows 10 / Edge 44 | mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > focus > (gotpointercapture ) > pointerup > mouseup > click > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave |
mousemove > pointerover > mouseover > pointerenter > mouseenter > pointerdown > mousedown > (gotpointercapture ) > pointerup > mouseup > click > (lostpointercapture ) > pointerout > mouseout > pointerleave > mouseleave |
blur |
Windows 10 / Edge 78.0.276.11 (beta) | pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mouseover > mouseenter > mousemove > mousedown > focus > mouseup > click |
pointerover > pointerenter > pointerdown > touchstart > (gotpointercapture ) > pointerup > (lostpointercapture ) > pointerout > pointerleave > touchend > mousemove > mousedown > mouseup > click |
mouseout > mouseleave > blur |
If during the tap there is too much movement of the finger (based on browser-specific threshold), this is considered a gesture rather than a tap. For browsers supporting Touch Events, no mouse compatibility events nor click
are generally fired.
In Windows 8.1/IE11, too much movement results in: mousemove
> pointerover
> mouseover
> pointerenter
> mouseenter
> pointerdown
> mousedown
> (gotpointercapture
) > focus
(if not previously focused) > pointerout
> mouseout
> pointerleave
> mouseleave
> pointercancel
> (lostpointercapture
) (note the fact that no pointerup
, mouseup
nor click
are fired).
In Windows 10 / IE (Edge) (build 10041) with Touch Events and Interop Mouse Events for Touch disabled, too much movement results in: mousemove
> pointerover
> mouseover
> pointerenter
> mouseenter
> pointerdown
> mousedown
> focus
(if not previously focused) > (gotpointercapture
) > pointercancel
> pointerout
> mouseout
> pointerleave
> mouseleave
> (lostpointercapture
) (note different order for focus
and pointercancel
).
In Windows 10 / IE (Edge) (build 10041) with Touch Events enabled, too much movement results in: mousemove
> pointerover
> mouseover
> pointerenter
> mouseenter
> pointerdown
> touchstart
> mousedown
> focus
(if not previously focused) > (gotpointercapture
) > (pointermove
> mousemove
> pointermove
> touchmove
> mousemove
) > pointercancel
> touchcancel
> pointerout
> mouseout
> pointerleave
> mouseleave
> (lostpointercapture
) (note the fact that three pointermove
, a single touchmove
and two mousemove
are fired).
In Windows 10 / IE (Edge) (build 10041) with Touch Events and Interop Mouse Events for Touch enabled, too much movement results in: pointerover
> pointerenter
> pointerdown
> touchstart
> (gotpointercapture
) > pointermove
> touchmove
> pointercancel
> touchcancel
> pointerout
> pointerleave
> (lostpointercapture
) (note absence of any focus
, even if element was not previously focused).
In addition, in Windows 10 / IE (Edge) (build 10041) with Interop Mouse Events for Touch enabled, touch-action:none
does not result anymore in mousemove
being fired when moving a touchscreen pointer.
The first preview of Windows 10 / Spartan (build 10049) behaves the same way as IE (Edge) with Touch Events and Interop Mouse Events for Touch enabled.
Windows 10 / Microsoft Edge has Touch events
and Mouse events for touch
disabled by default.
Desktop with assistive technology event order
Using traditional TAB / SHIFT+TAB / ENTER keyboard navigation. Notice the faked mouse events (particularly in OS X, when activating the test button with CTRL+⌥ ALT+SPACE as prompted by VoiceOver), which are not fired when assistive technology is not present, and are most likely meant for compatibility with sites that assume mouse interactions.
Included primarily as a point of comparison for the more specific case of desktop with touchscreen and assistive technology.
This table also includes classic Opera 12 (Presto) which has a unique spatial navigation feature (also used in Opera-based TV browsers): using SHIFT+cursor keys, this mode allows to set focus with the keyboard not in a sequential tab order, but based on the relative position of elements in the rendered layout (e.g. using SHIFT+→ to move to the closest focusable element to the right of the current element). Again, for compatibility with mouse-centric sites/scripts, Opera’s spatial navigation fires the whole range of mouse events when entering and leaving an element.
Browser | Move to button | 1st activation | 2nd activation | Leave button |
---|---|---|---|---|
Windows 8 / Chrome 34 + ChromeVox 1.31.4 | focus |
click (using ENTER or SPACE) mousedown > mouseup > click (using ChromeVox+SPACE) |
click (using ENTER or SPACE) mousedown > mouseup > click (using ChromeVox+SPACE) |
blur |
Windows 8 / Chrome 33 + JAWS 15 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 8 / Chrome 34 + NVDA 2014.1 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 8 / Chrome 33 + Narrator | focus |
click |
click |
blur |
Windows 8 / IE11 + JAWS 15 | focus |
click |
click |
blur |
Windows 8 / IE11 + NVDA 2014.1 | focus |
click |
click |
blur |
Windows 8 / IE11 + Narrator | focus |
click |
click |
blur |
Windows 8 / IE11 + ZoomText 10.1 | focus |
click |
click |
blur |
Windows 8 / Firefox 28 + JAWS 15 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 8 / Firefox 28 + NVDA 2014.1 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 8 / Firefox 28 + Narrator | focus |
click |
click |
blur |
Windows 8 / Firefox 28 + ZoomText 10.1 | focus |
click |
click |
blur |
Windows 8 / Opera 20 (Blink) + JAWS 15 | focus |
click |
click |
blur |
Windows 8 / Opera 20 (Blink) + NVDA 2014.1 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 8 / Opera 20 (Blink) + Narrator | focus |
click |
click |
blur |
Windows 8 / Opera 20 (Blink) + ZoomText 10.1 | focus |
click |
click |
blur |
Windows 8 / Opera 12 (Presto) + Spatial Navigation (SHIFT+cursor keys) |
focus > mouseenter > mouseover > mousemove |
click |
click |
blur > mouseout > mouseleave |
OS X 10.9.2 / Safari 7.0.2 + VoiceOver | focus |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
blur |
OS X 10.9.2 / Chrome 33 + VoiceOver | focus |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
blur |
OS X 10.9.2 / Firefox 29 + VoiceOver | focus |
click (using ENTER or SPACE) mousedown > blur > mouseup > click (using CTRL+⌥ ALT+SPACE) |
click (using ENTER or SPACE) mousedown >mouseup > click (using CTRL+⌥ ALT+SPACE) |
blur (if not activated or activated using ENTER or SPACE) none (if activated using CTRL+⌥ ALT+SPACE) |
Windows 10 / Microsoft Edge + NVDA 2015.1 | focus |
click |
click |
blur |
Windows 10 / Microsoft Edge + JAWS 16 | focus |
click |
click |
blur |
Windows 10 / Microsoft Edge + Narrator | focus |
click |
click |
blur |
Windows 10 / Chrome 53 + NVDA 2016.2.1 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Chrome 53 + JAWS 17 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Chrome 53 + Narrator | focus |
click |
click |
blur |
Windows 10 / Chrome 77 + NVDA 2019.2 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Chrome 77 + JAWS 2018 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Chrome 77 + Narrator (scan mode on) | focus > blur > focus |
blur > focus > blur > focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur |
Windows 10 / Firefox 69 + NVDA 2019.2 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Firefox 69 + JAWS 2018 | focus |
click |
click |
blur |
Windows 10 / Firefox 69 + Narrator (scan mode on) | focus > blur > focus |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Edge 44 + NVDA 2019.2 | focus |
pointerdown > mousedown > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
blur |
Windows 10 / Edge 44 + JAWS 2018 | focus |
none (bug) |
none (bug) |
blur |
Windows 10 / Edge 44 + Narrator (scan mode on) | none |
focus > pointerdown > mousedown > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
blur |
Windows 10 / Edge 79.0.279.0 (Dev) + NVDA 2019.2 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Edge 79.0.279.0 (Dev) + JAWS 2018 | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Edge 79.0.279.0 (Dev) + Narrator (scan mode on) | focus > blur > focus |
blur > focus > blur > focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur |
Chromebook Pixel / Chrome OS 69.0.3497.120 + ChromeVox | focus |
click |
click |
blur |
macOS Mojave 10.14.6 / Safari 13.0.1 + VoiceOver | focus |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
blur |
macOS Mojave 10.14.6 / Chrome 77 + VoiceOver | focus |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
click (using ENTER or SPACE) mousedown > mouseup > click (using CTRL+⌥ ALT+SPACE) |
blur |
When using VoiceOver on OS X, different events are fired depending on how elements are activated – for instance, activating a button with SPACE or ENTER will simply fire click
, whereas CTRL+ALT+SPACE (the key combination prompted by VoiceOver) also fires the aforementioned “faked” mouse events.
Similarly, switching between reading and forms mode in NVDA, or scan mode on/off in Narrator, can change the events fired.
Opera 12 (Presto) on Windows, OS X and Opera 20 (Blink) on OS X seem to have no (workable) support for assistive technology. ZoomText 10.1 currently not working at all with Chrome (34).
Recent versions of Firefox (Quantum) don’t seem to work at all with VoiceOver on macOS?
Desktop with touchscreen and assistive technology event order
Using touch gestures (e.g. swipe left/right, double-tap to activate) and “touch explore”, instead of traditional TAB / SHIFT+TAB / ENTER keyboard navigation.
Browser | Move to button | 1st activation | 2nd activation | Leave button |
---|---|---|---|---|
Windows 8 / Chrome 33 + JAWS 15 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / Chrome 33 + NVDA 2014.1 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / Chrome 33 + Narrator gesture navigation and touch explore | none |
focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / IE11 + JAWS 15 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > click |
click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / IE11 + NVDA 2014.1 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > click |
click |
none (not even when moving to/activating another element) |
Windows 8 / IE11 + Narrator gesture navigation and touch explore | none |
focus > click |
click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / Firefox 28 + JAWS 15 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / Firefox 28 + NVDA 2014.1 gesture navigation and touch explore (no visible outline / focus indication) | none |
mousedown > focus > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 8 / Firefox 28 + Narrator gesture navigation and touch explore | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / Opera 20 (Blink) + JAWS 15 gesture navigation (no visible outline / focus indication) [touch explore not working] | none |
focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / Opera 20 (Blink) + NVDA 2014.1 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 8 / Opera 20 (Blink) + Narrator gesture navigation [touch explore not working] | none |
focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 10 / Microsoft Edge + NVDA 2015.1 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > click |
click |
blur (only once moved to another focusable element and activated that element) |
Windows 10 / Microsoft Edge + JAWS 16 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > click |
click |
blur (only once moved to another focusable element and activated that element) |
Windows 10 / Microsoft Edge + Narrator gesture navigation and touch explore | none |
focus > click |
click |
blur (only once moved to another focusable element and activated that element) |
Windows 10 / Chrome 53 + NVDA 2016.2.1 gesture navigation and touch explore (no visible outline / focus indication) | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 10 / Chrome 53 + JAWS 17 gesture navigation/td> | none |
focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 10 / Chrome 53 + Narrator gesture navigation and touch explore | none |
focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur (only once moved to another focusable element and activated that element) |
Windows 10 / Chrome 77 + NVDA 2019.2 gesture navigation | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Chrome 77 + Narrator (scan mode on) gesture navigation | none |
focus > blur > focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur |
Windows 10 / Chrome 77 + JAWS 2018 gesture navigation | none |
focus > mousedown > mouseup > click |
blur > focus **mousedown > mouseup > click |
blur |
Windows 10 / Firefox 69 + NVDA 2019.2 gesture navigation | none |
touchstart > mousedown > focus > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur |
Windows 10 / Firefox 69 + Narrator (scan mode on) gesture navigation | none |
focus > touchstart > mousedown > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur |
Windows 10 / Firefox 69 + JAWS 2018 gesture navigation | none |
focus > touchstart > mousedown > touchend > mouseup > click |
touchstart > mousedown > touchend > mouseup > click |
blur |
Windows 10 / Edge 44 + NVDA 2019.2 gesture navigation | none |
focus > pointerdown > mousedown > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
blur |
Windows 10 / Edge 44 + Narrator (scan mode on) gesture navigation | none |
focus > pointerdown > mousedown > pointerup > mouseup > click |
pointerdown > mousedown > pointerup > mouseup > click |
blur |
Windows 10 / Edge 44 + JAWS 2018 gesture navigation | none |
none (bug) |
none (bug) |
none |
Windows 10 / Edge 79.0.279.0 (Dev) + NVDA 2019.2 gesture navigation | none |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Windows 10 / Edge 79.0.279.0 (Dev) + Narrator (scan mode on) gesture navigation | none |
focus > blur > focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur |
Windows 10 / Edge 79.0.279.0 (Dev) + JAWS 2018 gesture navigation | none |
focus > mousedown > mouseup > click |
blur > focus > mousedown > mouseup > click |
blur |
Chromebook Pixel / Chrome OS 69.0.3497.120 + ChromeVox gesture navigation | focus |
mousedown > mouseup > click |
mousedown > mouseup > click |
blur |
Chromebook Pixel / Chrome OS 69.0.3497.120 + ChromeVox (touch to explore to move to / away from control) | pointerover > pointerenter >mouseover > mouseenter > (pointermove > mousemove )+ |
focus > mousedown > mouseup > click |
mousedown > mouseup > click |
pointerout > pointerleave > mouseout > mouseleave |
Using a desktop screenreader with a touchscreen and touch gestures (swipe left/right and using “touch explore”, similar to mobile/tablet screenreaders), none of the tested combinations of browser/AT fired a focus
event when moving the focus outline to an element – focus
is only sent as a result of a double-tap activation.
Opera 12 (Presto) on Windows seems to have no support for assistive technology. Chrome+ChromeVox does not currently support touch swipes/gestures on desktop.
Suppressing 300ms delay for touchscreen interactions
Small series of tests to check which of the “tricks” used to suppress the dreaded 300ms delay (for Touch Events, between touchend
and the compatibility mouse events, including click
; for Pointer Events, just before the click
) actually works in various browsers/OSs. Where known, this also includes the particular version of the browser that added support, with reference to the related bug/announcement. Blank cells mean that a particular trick/technique has no effect and that the 300ms delay is still present. (Note that, to be precise, on iOS the delay is actually 350ms)
Browser | <meta name="viewport" content="user-scalable=no"> |
<meta name="viewport" content="minimum-scale=1,maximum-scale=1"> |
<meta name="viewport" content="width=device-width"> |
touch-action:none |
touch-action:manipulation |
---|---|---|---|---|---|
iOS 9.3 / Safari/WebView | Yes (iOS 9.3) |
Yes (iOS 9.3) |
Yes (iOS 9.3 - except if content is zoomed in beyond initial value) |
Yes (iOS 9.3 - only if applied to actual clickable element, see Bug 149854 comment #25) |
|
iOS 10 / Safari/WebView | Yes (iOS 9.3 - except if content is zoomed in beyond initial value) |
Yes (iOS 9.3 - only if applied to actual clickable element, see Bug 149854 comment #25) |
|||
Android 4.3 / Browser (WebKit 534.30) | |||||
Android 6 / Dolphin 11.5 | |||||
Android 6 / UC Browser 10.8 | Yes | ||||
Android 6 / Chrome 47 | Yes (Chrome 24+) |
Yes (Chrome 24+) |
Yes (Chrome 32+ - except if content is wider than viewport) |
Yes (Chrome 35+) |
Yes (Chrome 35+) |
Android 6 / Opera 4.3 | Yes | Yes | Yes | Yes | Yes |
Android / Firefox 43 | Yes | Yes | Yes (Firefox 30+) |
||
Blackberry (BBOS 10) / Browser | Yes (BBOS 10.1) |
Yes (BBOS 10.3) |
Yes (BBOS 10.3) |
||
Firefox OS 2.0 (indirectly tested, so may be inaccurate) |
Yes (Firefox OS 2.0+) |
Yes (Firefox OS 1.4+) |
|||
Windows Phone 8.1 / IE 11 | Yes (IE11+) |
Yes (IE11+) |
Yes (IE10 -ms-touch-action , IE11+ unprefixed) |
Yes (IE10 -ms-touch-action , IE11+ unprefixed) |
|
Windows 10 Mobile / Microsoft Edge | Yes | Yes | Yes | Yes | Yes |
Windows 8.1 / Chrome 37 | N/A | N/A | N/A | N/A | N/A |
Windows 8.1 / Firefox 32 | N/A | N/A | N/A | N/A | N/A |
Windows 8.1 / IE 11 | Yes (IE10 -ms-touch-action , IE11+ unprefixed) |
Yes (IE10 -ms-touch-action , IE11+ unprefixed) |
|||
Windows 10 / Microsoft Edge | Yes | Yes | |||
Amazon Fire OS 5.3.3.0 (Android 5.1.1) / Silk Browser 58.2.6.3029.83.10 | Yes | Yes | Yes | Yes | Yes |
Android 6.0.1 / Samsung Internet for Android 4.0.20-6 | Yes | Yes | Yes | Yes | |
Android 6.0.1 / Samsung Internet for Android 5.4.00-70 (Beta) | Yes | Yes | Yes | Yes | Yes |
Android 6.0.1 / Samsung Internet 5.4.00-75 | Yes | Yes | Yes | ||
Android 10 / Chrome 77 | Yes unless user toggled Settings > Accessibility > Force enable zoom |
Yes unless user toggled Settings > Accessibility > Force enable zoom |
Yes | Yes | Yes |
Android 10 / Firefox 68.1.1 | Yes | Yes | Yes | Yes | Yes |
Android 10 / Samsung Internet 10.1 | Yes | Yes | Yes | ||
Android 10 / Edge 42 | Yes unless user toggled Settings > Accessibility > Force zoom |
Yes unless user toggled Settings > Accessibility > Force zoom |
Yes | Yes | Yes |
iOS 13.1 / Safari/WebView + keyboard | Yes | Yes | Yes | Yes |
In short, the suggested approach for all modern browsers is to use a combination of <meta name="viewport" content="width=device-width">
(which you’re likely to be already using anyway for mobile-friendly sites) and, if needed, explicit use of touch-action:manipulation
on instant controls (such as links or buttons).
To work around 300ms delay in situations where none of the tricks/techniques are supported - in particular, on older iOS/WebKit - developers will have to resort to explicit JavaScript handling (e.g. listening to touchend
- which fires as soon as a touch point on a touchscreen is lifted, and before the 300ms delay - and suppressing mouse compatibility and click
events), being mindful of not making naive “touch or mouse” assumptions - see Detecting touch: it’s the ‘why’, not the ‘how’. In most cases, simply dropping in FTLabs’ fastclick (or using a custom event handler like tap.js) should achieve the desired result with minimal effort.
iOS 10 update: Safari now ignores user-scalable=no
, minimum-scale=1, maximum-scale=1
and similar - by default, users are always able to zoom. The 300ms optimization that was present in 9.3 for these two cases does not work in Safari anymore. For embedded WebViews, these viewport directives supposedly still work (not tested), so it is possible that in these cases (e.g. for hybrid native/web applications) the optimization will still occur.
iOS 9.3 update: this release finally included some of the common ways in which to suppress the delay (Bug 150604 - Implement viewport-width-based fast-click heuristic, Bug 149968 - Web pages with unscalable viewports shouldn’t have a single tap delay) and Bug 149854 - Implement touch-action: manipulation; for iOS). See WebKit blog: More Responsive Tapping on iOS.
iOS 8 update: it seems that in iOS 8, some heuristics have been included in Safari that prevent the 300ms delay from happening depending on the duration of the touch/tap. Fast taps have 300ms delay (as they’re more likely to be the first of a quick double-tap, presumably), while slightly slower taps (if the delay between touchstart
and touchend
is above a certain threshold, around 125ms, without too much movement) fire the mouse compatibility events instantly (see Disable FastClick on iOS 8 #262 and my short video iOS 8/Safari 300ms delay heuristics). It seems this only happens in Safari, and not in the generic UIWebView, so other browsers like iOS/Chrome still have the delay regardless of tap speed - however, it’s likely present in WKWebView and will roll into other browsers when they upgrade to this. Update: rather than an explict heuristic, this is more of a side effect of a change in iOS’ gesture recogniser.
Also, in a change from iOS 7, innerHTML
now also seems to count as a “content change” (see The iOS event cascade and innerHTML)so my tests will need to be updated, as currently no click
event is being fired on them.
iOS/WebKit update (December 2015): all relevant bugs (Bug 150604, Bug 149968) and Bug 149854) are now RESOLVED FIXED
. See More Responsive Tapping on iOS. However, no indication has yet been given when these changes will find their way into iOS - all signs are still pointing towards a future iOS 10 release (since Apple don’t historically make such wide-sweeping changes in iOS point releases).
iOS 9.3 Preview (January 2016) now includes the viewport and touch-action:manipulation
optimisations.
On Windows 8.1 and Windows 10 on a touchscreen device, Chrome and Firefox do not currently support “double-tap to zoom”, so no 300ms delay is present (hence the “N/A” entries in the table). Internet Explorer and Microsoft Edge, on the other hand, does support “double-tap to zoom”, so touch-optimisations to remove the delay (using touch-action:manipulation
) will also be necessary on desktop. Also note that viewport
is not supported/ignored on desktop in IE/Edge (with some exception when it comes to “Metro” snap mode), so pages using those viewport
directives are still zoomable - “double-tap to zoom” still works in these cases, but cannot be prevented by merely adding viewport
.
Samsung Internet for Android’s default delay is considerably lower than 300ms - on average, closer to 190ms.
“Faked” event coordinates
As noted in the “Desktop with assistive technology” and “Desktop with touchscreen and assistive technology” sections, even when not using a traditional pointing device, certain combinations of browser/AT generate “fake” mouse events for compatibility with legacy sites/scripts that hang behavior on traditional mouse events.
As part of an admittedly philosophical discussion on whether or not setting focus with a keyboard or screenreader (jumping from one focusable element to the next, usually in linear tab order) could also be considered an act of “pointing” (and as such should generate pointer events - see Bug 24786 - ACTION-64: Propose a non-normative note re the keyboard compat issue), I tested if these “faked” events, as well as the final click
, also carry any coordinates in their event object.
Any combinations of browser/AT not listed in this table do not generate “fake” mouse events, and any traditional focus
, click
, blur
events they do fire do not contain any coordinates in their event object, as would be the case with regular keyboard interactions.
Browser | Events fired on activation (unless otherwise noted) |
Coordinates |
---|---|---|
iOS 7.1 / Safari/WebView + VoiceOver | touchstart > touchend > mouseover > mousemove > mousedown > (blur ) > mouseup > click mouseleave > mouseout (when moving to another focusable/activatable element) |
center of element center of the new element that received focus (when moving to another focusable/activatable element) |
Android 4.3 / Chrome M34 + TalkBack (effectively ChromeVox) only touch explore | mouseenter > mouseover > (mousemove )+ > (focus )(when moving to element using “touch explore”) ( mousemove )+ > mouseleave > mouseout (when moving away from element using “touch expore”) |
screenX /screenY are 0 clientX /clientY and pageX /pageY correspond to finger position |
Android 4.3 / Firefox 28 + TalkBack using swipe gestures | touchstart > mousedown > (focus ) > touchend > mouseup > click |
center of element |
Android 4.3 / Firefox 28 + TalkBack using touch explore | mouseover (when moving to element using “touch explore”) mouseout (when moving away from element using “touch expore”) |
finger position |
Windows 8 / Chrome 34 + ChromeVox 1.34.1 | mousedown > mouseup > click (using ChromeVox+SPACE) |
none |
Windows 8 / Chrome 34 + JAWS 15 | mousedown > mouseup > click |
none |
Windows 8 / Chrome 34 + JAWS 15 gesture navigation | mousedown > mouseup > click |
none |
Windows 8 / Chrome 34 + NVDA 2014.1 | mousedown > mouseup > click (using SPACE) |
none |
Windows 8 / Chrome 34 + NVDA 2014.1 gesture navigation | mousedown > mouseup > click |
none |
Windows 8 / Chrome 34 + Narrator gesture navigation | mousedown > mouseup > click |
none |
Windows 8 / Firefox 28 + JAWS 15 | mousedown > mouseup > click |
center of element |
Windows 8 / Firefox 28 + JAWS 15 gesture navigation | mousedown > mouseup > click |
center of element |
Windows 8 / Firefox 28 + NVDA 2014.1 | mousedown > mouseup > click |
center of element |
Windows 8 / Firefox 28 + NVDA 2014.1 gesture navigation | mousedown > mouseup > click |
center of element |
Windows 8 / Firefox 28 + Narrator touchscreen | mousedown > mouseup > click |
center of element |
Windows 8 / Opera 20 (Blink) + Narrator gesture navigation | mousedown > mouseup > click |
none |
Windows 8 / Opera 20 (Blink) + JAWS 15 gesture navigation | mousedown > mouseup > click |
none |
Windows 8 / Opera 20 (Blink) + NVDA 2014.1 | mousedown > mouseup > click |
none |
Windows 8 / Opera 20 (Blink) + NVDA 2014.1 gesture navigation | mousedown > mouseup > click |
none |
Windows 8 / Opera 12 (Presto) Spatial Navigation | focus > mouseenter > mouseover > mousemove (when focusing) click (when activating) mouseout > mouseleave > blur (when leaving) |
top left corner of element |
Windows Phone 8.1 Update 1 / IE11 + Narrator | focus > click |
none |
Windows 10 Mobile (Insider Preview 10149) / Microsoft Edge + Narrator | click |
none |
Windows 10 / Microsoft Edge + NVDA 2015.1 | click |
none |
Windows 10 / Microsoft Edge + JAWS 16 | click |
none |
Windows 10 / Microsoft Edge + Narrator | click |
none |
One interesting result which is not included in this table (as it’s likely a bug): even for traditional keyboard navigation (with and without Narrator), IE11 passes along coordinates in the event object for the click
event when an element is activated. However, these coordinates are meaningless - see Bug 856583: IE11 click event has strange/illogical screenX/screenY, clientX/clientY, pageX/pageY coordinates:
- using ENTER
screenX
/screenY
are0
- using SPACE
screenX
/screenY
are screen coordinates of top left corner of the browser viewport clientX
/clientY
andpageX
/pageY
contain negative values, the inverse of the coordinates of the top left corner of browser viewport