auxclick is coming to Chrome 55

When is a click not a click? For a web developer working on a complex user interface, that's not an abstract philosophical question. If you're implementing custom mouse input behavior, it's crucial to keep user intent in mind. If a user clicks on a link with their mouse's middle button, for instance, then it's reasonable to assume that they wanted to open a new tab with that link's contents. If a user middle-clicks on a random UI element, then it you may want to assume that it was inadvertent, and ignore that input, while a primary button click would be expected to trigger a response from the UI.

It's possible, if a bit cumbersome, to model these nuanced interactions via a single click event listener. You would have to explicitly check the button property of the MouseEvent, to see whether it was set to 0, representing the primary button, versus anything else, with 1 usually representing the middle button, and so on. But not many developers go as far as explicitly checking the button property, leading to code that handles all clicks identically, regardless of which button was pressed.

Starting with Chrome 55, a new type of MouseEvent, called auxclick, is fired in response to any clicks made with a non-primary button. Accompanying this new event is a corresponding change in behavior of the click event: it will only fire when the primary mouse button is pressed. We hope that these changes will make it easier for web developers to write event handlers that respond to only the type of clicks that they care about, without having to specifically check the MouseEvent.button property.

Reduce false positives

As mentioned, one motivation for creating auxclick was to avoid deployment of custom click handlers that mistakenly override the "middle-click-opens-a-tab" behavior. For example, imagine that you've written a click event handler that uses the History API to rewrite the location bar, and implement custom single-page navigations. It might look something like:

document.querySelector('#my-link').addEventListener('click', event => {
    event.preventDefault();
    // ...call history.pushState(), use client-side rendering, etc....
});

Your custom logic might work as intended when triggered by a mouse's primary button, but if that code runs when a middle button is clicked, it's effectively a false positive. Prior to the new behavior, you'd end up preventing the default action of opening a new tab, which runs counter to your user's expectations. While you could explicitly check for event.button === 0 at the start of your handler, and only execute the code if that's the case, it's easy to forget, or never realize it's necessary to do that.

Only run the code you need

The flip side of fewer false positives is that auxclick callbacks will only run when there's actually a non-primary mouse button clicked. If you have code that needs to, for example, calculate an appropriate destination URL before opening a new tab, you can listen for auxclick and include that logic in your callback. It won't incur the overhead of being run when the primary mouse button is clicked.

Browser support and compatibility

This new behavior is currently only implemented in Chrome 55. As mentioned in the initial proposal, feedback (both positive and negative) from the web developer community is appreciated. Filing a GitHub issue is the best way to share that feedback with the folks who are working on the standardization process.

In the meantime, developers don't have to wait for auxclick to be widely available to follow some best practices for handling mouse events. If you take the time to check the value of the MouseEvent.button property at the start of your click event handler, you can ensure that you take appropriate action. The following pattern will handle primary and auxiliary clicks differently, whether or not there's native support for auxclick:

function handlePrimaryClick(event) {
    // ...code to handle the primary button click...
}

function handleAuxClick(event) {
    // ...code to handle the auxiliary button click….
}

document.querySelector('#my-link').addEventListener('click', event => {
    if (event.button === 0) {
    return handlePrimaryClick(event);
    }


    // This provides fallback behavior in browsers without auxclick.
    return handleAuxClick(event);
});

// Explicitly listen for auxclick in browsers that support it.
document.querySelector('#my-link').addEventListener('auxclick', handleAuxClick);