loading...
Cover image for Consistent access to browser events with Pointer Events API

Consistent access to browser events with Pointer Events API

pfacklam profile image Paul Facklam ・3 min read

Thank god it's christmas! 🌲 Ok, it's not. But if you're a web developer nowadays, it's starting to feel like christmas. And it's because of this:

Added support for the Pointer Events API enabling consistent access to mouse, trackpad, touch, and Apple Pencil events.

-- Safari 13 Release Notes

Thus the last resistance against the Pointer Events API has fallen with Safari 13 and it's now available across all major browsers. And this is simply awesome!

But don't thank Apple! Belive it or not, pointer events (which are not to be mixed up with the CSS property pointer-events) were originally introduced for the Internet Explorer 10 by Microsoft for their Surface devices. 😳

How does it work?

Having a single event model for pointers can simplify creating Web sites and applications and provide a good user experience regardless of the user's hardware.

-- Mozilla Developer Network

Roughly speaking, mouse and touch events are summarized by abstracting input devices like mouse and touch pens as pointing devices. So you don't need to specify different event handlers for different device types any longer.

document.addEventListener('mousedown', () => {
  // do something on mousedown
});

document.addEventListener('touchdown', () => {
  // do something on touchdown
});

Instead you can now simply apply one handler to rule them all.

document.addEventListener('pointerdown', () => {
  // do something on mousedown or touchdown
});

You might now ask: "But can I still react to different device types?" Yes, you can! That's what the pointerType property of the event is for.

document.addEventListener('pointerdown', (e) => {
  switch (e.pointerType) {
    case 'mouse': {
      console.log('Pointer type detected: mouse');
      break;
    }
    case 'pen': {
      console.log('Pointer type detected: pen');
      break;
    }
    case 'touch': {
      console.log('Pointer type detected: touch');
      break;
    }
    default: {
      console.log('PointerType is unknown or could not be detected');
    }
  }
});

A look at the API

The PointerEvent interface extends the MouseEvent interface and defines 10 different pointer event types that can be mapped to more or less known mouse or touch events and which are well documented at MDN:

Pointer Event Mouse Event
pointerover mouseover
pointerover mouseover
pointerenter mouseenter
pointerdown mousedown
pointermove mousemove
pointerup mouseup
pointercancel no equivalent
pointerout mouseout
pointerleave mouseleave
gotpointercapture no equivalent
lostpointercapture no equivalent

You also have access to the following read-only properties which give you some additional information about the event:

Property Description
pointerId a unique identifier for the pointer
width magnitude on the X axis in pixels
height magnitude on the Y axis in pixels
pressure normalized pressure of the pointer input
tangentialPressure normalized tangential pressure of the pointer input
tiltX angle between the Y-Z plane and the plane containing both the pointer axis and the Y axis
tiltY angle between the X-Z plane and the plane containing both the pointer axis and the X axis.
twist the clockwise rotation of the pointer
pointerType indicates the device type
isPrimary indicates if the pointer represents the primary pointer of this pointer type

Polyfill

If you have to support browsers that haven't yet implemented the Pointer Events API you can easily use a polyfill maintained by the jQuery team. But you can also do some basic feature detection and go with a fallback solution instead.

if (window.PointerEvent) {
  // Hello Pointer Events
} else {
  // Oh... Hi fallback... it's you.
}

Thanks for reading this article. I hope you'll enjoy using the Pointer Events API like I do. What are your thoughts about this? Tell me in the comments section below!

Discussion

markdown guide
 

Seems like there is no touchdown event?

 
 

So, is it better to change the following code like this?

document.addEventListener('touchdown', () => {
  // do something on touchdown
});

// =>

document.addEventListener('touchstart', () => {
  // do something on touchstart
});

If you still want to use touch events: yes. But you can also use pointerdown.