Skip to content

<blog>
Touch, click... pointer

Chris Mauck

April 30, 2015 • 3 minute read

A problem that has plagued developers since the inception of the touch device, is properly emulating interaction whether the user has a mouse or are using their finger. Why has it been a problem? Is it really necessary to work around this "issue"? If it is necessary, how complex must the solution be and can it encompass all devices, and perhaps future innovations that are currently being considered for adoption into the spec?

Background

Historically this has been a problem because touch events register instantly with the browser/device. Whereas click events have generally had a 300ms delay. This was initially instituted by Apple as a default in order to allow the browser/device to distinguish between a single or double click. The reason we've always worked to get around this issue is that continuous 300ms delays between interaction and resultant action lead the user to believe that your code is broken.

Primitive - but valid

Originally, it seemed that the easiest solution would be to create a variable related to the click event. This variable would be set based on the type of browser, or it's functionality and would in turn effect the type of event listener being added throughout the code.

// create a variable
let touchClick = '';
// check for "ontouchstart" in the DOM
if ("ontouchstart" in document.documentElement) {
    // if it exists, use it
    touchClick = "touchend";
} else {
    // if not, default to click
    touchClick = "click";
}

The problem

For simple development, or single platform targets, this works and it works well. However, what about devices that have both touch and mouse events? Well, a simple look at the code above should inform that. The first condition checks for the presence of "ontouchstart" within the DOM. If it exists, the code assumes that will be the method of interaction.

You may say "But wait, my device has touch events, but I am usually using a mouse." Well, you're not the only one. In fact, if this is the only method that you are using to check for touch events, and react to them, then you will quickly learn that your code has fallen short. Your experience will break if a user has touch events but is using a mouse, and you will have lost a visitor to your site or potential user of your product.

What Can Be Done?

Don't throw your hands in the air and give up just yet! There is a way that we can reliably check for not only touch events, but also pointer events.

The pointerEvent object

Because of the concern over touch and mouse events not being universally understood by browsers/devices, Microsoft introduced a new concept to the development world - pointer events and the pointerEvent object. The pointer events recognize whichever input medium you are imploring and utilize the best technology for the job. So, a mouse event would be a click, a touch by a finger or pen input device would register as a touch, etc.

Microsoft has proposed the addition of pointer events to the official specification [http://www.w3.org/TR/pointerevents/] on May 9, 2013, but they have not been adopted completely as of this writing. However, for devices that recognize events of this type, such as the Microsoft Surface, you can begin using these events today.

// create a variable
let touchClick = '';
// check for "pointer events" in the DOM
if (window.PointerEvent) {
    // if they exist, use them
    touchClick = "pointerup";
} else {
    // if not, default to click
    touchClick = "click";
}

Pretty similar to what we did for touch events right? In fact, let's clean the code up a little bit and make it more compact. We can start by setting the touchClick variable to "click" by default and only change it if the event we are looking for exists. Let's try that with our touch events first.

// create a variable
let touchClick = 'click';
// check for "ontouchstart" in the DOM
if ("ontouchstart" in document.documentElement) {
    // if it exists, use it
    touchClick = "touchend";
}

Straight to the point, and it gets rid of some of the cruft. Nice! We could do the same for the pointer events example, or we can combine the two to ensure universal acceptance of our code. Let's look at that:

// create a variable
let touchClick = 'click';
// check for "ontouchstart" in the DOM
if ("ontouchstart" in document.documentElement) {
    // if it exists, use it
    touchClick = "touchend";
}
// check for pointer events
if (window.PointerEvent) {
    // change again if valid
    touchClick = "pointerup";
}

Note: Starting with Windows 8, IE includes a method for disabling the default behavior of touch events and forcing the use of JavaScript to interpret the interactions. You can use the CSS touch-action property to disable default events on regions of a page or the entire page. For example:

#container {
    touch-action: none;
}

Keep in mind that the JavaScript examples above are only setting a single variable to be modified. In our case it is click on desktop or mouse events and touchend/pointerup at the end of an interaction on devices that support it. Additional variables can be set for other listeners to fully flesh out all interactions. But, I think I'll leave that for you.

For a complete list of the pointerEvent interactions, check out pointer events on MSDN. For a look into the pointerEvent object, hop on over to pointerEvent object also on MSDN.