diff --git a/packages/react-dom/src/client/ReactDOMClientInjection.js b/packages/react-dom/src/client/ReactDOMClientInjection.js
index cb4d2315f4cd2..49e10b3ed11e2 100644
--- a/packages/react-dom/src/client/ReactDOMClientInjection.js
+++ b/packages/react-dom/src/client/ReactDOMClientInjection.js
@@ -9,6 +9,7 @@ import * as EventPluginHub from 'events/EventPluginHub';
import * as EventPluginUtils from 'events/EventPluginUtils';
import * as ReactDOMComponentTree from './ReactDOMComponentTree';
+import AuxClickEventPlugin from '../events/AuxClickEventPlugin';
import BeforeInputEventPlugin from '../events/BeforeInputEventPlugin';
import ChangeEventPlugin from '../events/ChangeEventPlugin';
import DOMEventPluginOrder from '../events/DOMEventPluginOrder';
@@ -32,6 +33,7 @@ EventPluginUtils.injection.injectComponentTree(ReactDOMComponentTree);
*/
EventPluginHub.injection.injectEventPluginsByName({
SimpleEventPlugin: SimpleEventPlugin,
+ AuxClickEventPlugin: AuxClickEventPlugin,
EnterLeaveEventPlugin: EnterLeaveEventPlugin,
ChangeEventPlugin: ChangeEventPlugin,
SelectEventPlugin: SelectEventPlugin,
diff --git a/packages/react-dom/src/events/AuxClickEventPlugin.js b/packages/react-dom/src/events/AuxClickEventPlugin.js
new file mode 100644
index 0000000000000..5fcd19f111067
--- /dev/null
+++ b/packages/react-dom/src/events/AuxClickEventPlugin.js
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2013-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ */
+
+import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
+
+import SyntheticMouseEvent from './SyntheticMouseEvent';
+
+const eventTypes = {
+ auxClick: {
+ phasedRegistrationNames: {
+ bubbled: 'onAuxClick',
+ captured: 'onAuxClickCapture',
+ },
+ dependencies: ['topAuxClick', 'topClick'],
+ },
+};
+
+const AuxClickEventPlugin = {
+ eventTypes,
+
+ extractEvents(
+ topLevelType: mixed,
+ targetInst: mixed,
+ nativeEvent: MouseEvent,
+ nativeEventTarget: EventTarget,
+ ) {
+ if (topLevelType === 'topClick' && nativeEvent.button === 0) {
+ return null;
+ }
+
+ let event = SyntheticMouseEvent.getPooled(
+ eventTypes.auxClick,
+ targetInst,
+ nativeEvent,
+ nativeEventTarget,
+ );
+ event.type = 'auxclick';
+
+ accumulateTwoPhaseDispatches(event);
+ return event;
+ },
+};
+
+export default AuxClickEventPlugin;
diff --git a/packages/react-dom/src/events/BrowserEventConstants.js b/packages/react-dom/src/events/BrowserEventConstants.js
index 276df6ee76f22..179b5a7efbe40 100644
--- a/packages/react-dom/src/events/BrowserEventConstants.js
+++ b/packages/react-dom/src/events/BrowserEventConstants.js
@@ -21,6 +21,7 @@ var topLevelTypes = {
getVendorPrefixedEventName('animationiteration') || 'animationiteration',
topAnimationStart:
getVendorPrefixedEventName('animationstart') || 'animationstart',
+ topAuxClick: 'auxclick',
topBlur: 'blur',
topCancel: 'cancel',
topCanPlay: 'canplay',
diff --git a/packages/react-dom/src/events/DOMEventPluginOrder.js b/packages/react-dom/src/events/DOMEventPluginOrder.js
index bc7052f324643..e7583a2ce896f 100644
--- a/packages/react-dom/src/events/DOMEventPluginOrder.js
+++ b/packages/react-dom/src/events/DOMEventPluginOrder.js
@@ -17,6 +17,7 @@
var DOMEventPluginOrder = [
'ResponderEventPlugin',
'SimpleEventPlugin',
+ 'AuxClickEventPlugin',
'TapEventPlugin',
'EnterLeaveEventPlugin',
'ChangeEventPlugin',
diff --git a/packages/react-dom/src/events/__tests__/AuxClickEventPlugin-test.js b/packages/react-dom/src/events/__tests__/AuxClickEventPlugin-test.js
new file mode 100644
index 0000000000000..efe040ae70c5f
--- /dev/null
+++ b/packages/react-dom/src/events/__tests__/AuxClickEventPlugin-test.js
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2013-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+
+describe('AuxClickEventPlugin', () => {
+ var container;
+
+ beforeEach(() => {
+ jest.resetModules();
+
+ React = require('react');
+ ReactDOM = require('react-dom');
+
+ // The container has to be attached for events to fire.
+ container = document.createElement('div');
+ document.body.appendChild(container);
+ });
+
+ afterEach(() => {
+ document.body.removeChild(container);
+ container = null;
+ });
+
+ it('should not fire auxclick on primary mouse button click', () => {
+ let cb = jest.fn();
+ let node = ReactDOM.render(, container);
+
+ node.dispatchEvent(
+ new MouseEvent('click', {
+ bubbles: true,
+ cancelable: true,
+ button: 0,
+ }),
+ );
+
+ expect(cb).not.toBeCalled();
+ });
+
+ it('should fire auxclick on secondary mouse button click', () => {
+ let cb = jest.fn();
+ let node = ReactDOM.render(, container);
+
+ node.dispatchEvent(
+ new MouseEvent('click', {
+ bubbles: true,
+ cancelable: true,
+ button: 1,
+ }),
+ );
+
+ expect(cb).toBeCalled();
+ });
+
+ it('should respond to native auxclick', () => {
+ let cb = jest.fn();
+ let node = ReactDOM.render(, container);
+
+ node.dispatchEvent(
+ new MouseEvent('auxclick', {
+ bubbles: true,
+ cancelable: true,
+ button: 1,
+ }),
+ );
+
+ expect(cb).toBeCalled();
+ });
+});