diff --git a/Gruntfile.js b/Gruntfile.js
index bbb71d33e52..4f7dcc73e7f 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -247,9 +247,6 @@ grunt.initConfig( {
 
 				"requirejs/require.js": "requirejs/require.js",
 
-				"jquery-mousewheel/jquery.mousewheel.js": "jquery-mousewheel/jquery.mousewheel.js",
-				"jquery-mousewheel/LICENSE.txt": "jquery-mousewheel/LICENSE.txt",
-
 				"jquery-simulate/jquery.simulate.js": "jquery-simulate/jquery.simulate.js",
 				"jquery-simulate/LICENSE.txt": "jquery-simulate/LICENSE.txt",
 
diff --git a/bower.json b/bower.json
index eec454dea05..3ed76cee9c3 100644
--- a/bower.json
+++ b/bower.json
@@ -13,7 +13,6 @@
 	},
 	"devDependencies": {
 		"jquery-color": "3.0.0",
-		"jquery-mousewheel": "3.1.12",
 		"jquery-simulate": "1.1.1",
 		"qunit": "2.19.4",
 		"requirejs": "2.1.14",
diff --git a/demos/spinner/currency.html b/demos/spinner/currency.html
index 4180b12e111..fa3744ba51c 100644
--- a/demos/spinner/currency.html
+++ b/demos/spinner/currency.html
@@ -7,7 +7,7 @@
 	<link rel="stylesheet" href="../../themes/base/all.css">
 	<link rel="stylesheet" href="../demos.css">
 	<script src="../../external/requirejs/require.js"></script>
-	<script src="../bootstrap.js" data-modules="external/globalize/globalize external/globalize/globalize.culture.de-DE external/globalize/globalize.culture.ja-JP external/jquery-mousewheel/jquery.mousewheel">
+	<script src="../bootstrap.js" data-modules="external/globalize/globalize external/globalize/globalize.culture.de-DE external/globalize/globalize.culture.ja-JP">
 		$( "#currency" ).on( "change", function() {
 			$( "#spinner" ).spinner( "option", "culture", $( this ).val() );
 		});
diff --git a/demos/spinner/decimal.html b/demos/spinner/decimal.html
index 0b39f2bac33..af86bbbe796 100644
--- a/demos/spinner/decimal.html
+++ b/demos/spinner/decimal.html
@@ -7,7 +7,7 @@
 	<link rel="stylesheet" href="../../themes/base/all.css">
 	<link rel="stylesheet" href="../demos.css">
 	<script src="../../external/requirejs/require.js"></script>
-	<script src="../bootstrap.js" data-modules="external/globalize/globalize external/globalize/globalize.culture.de-DE external/globalize/globalize.culture.ja-JP external/jquery-mousewheel/jquery.mousewheel">
+	<script src="../bootstrap.js" data-modules="external/globalize/globalize external/globalize/globalize.culture.de-DE external/globalize/globalize.culture.ja-JP">
 		$( "#spinner" ).spinner({
 			step: 0.01,
 			numberFormat: "n"
diff --git a/demos/spinner/default.html b/demos/spinner/default.html
index 39684fb5efc..2011b84ba85 100644
--- a/demos/spinner/default.html
+++ b/demos/spinner/default.html
@@ -7,7 +7,7 @@
 	<link rel="stylesheet" href="../../themes/base/all.css">
 	<link rel="stylesheet" href="../demos.css">
 	<script src="../../external/requirejs/require.js"></script>
-	<script src="../bootstrap.js" data-modules="external/jquery-mousewheel/jquery.mousewheel">
+	<script src="../bootstrap.js">
 		var spinner = $( "#spinner" ).spinner();
 
 		$( "#disable" ).on( "click", function() {
diff --git a/demos/spinner/latlong.html b/demos/spinner/latlong.html
index 0ee747eee54..cdaf65f3c62 100644
--- a/demos/spinner/latlong.html
+++ b/demos/spinner/latlong.html
@@ -8,7 +8,7 @@
 	<link rel="stylesheet" href="../demos.css">
 	<script src="https://maps.google.com/maps/api/js?sensor=false"></script>
 	<script src="../../external/requirejs/require.js"></script>
-	<script src="../bootstrap.js" data-modules="external/jquery-mousewheel/jquery.mousewheel">
+	<script src="../bootstrap.js">
 		function latlong() {
 			return new google.maps.LatLng( $("#lat").val(), $("#lng").val() );
 		}
diff --git a/demos/spinner/overflow.html b/demos/spinner/overflow.html
index 1def62da053..76e10783691 100644
--- a/demos/spinner/overflow.html
+++ b/demos/spinner/overflow.html
@@ -7,7 +7,7 @@
 	<link rel="stylesheet" href="../../themes/base/all.css">
 	<link rel="stylesheet" href="../demos.css">
 	<script src="../../external/requirejs/require.js"></script>
-	<script src="../bootstrap.js" data-modules="external/jquery-mousewheel/jquery.mousewheel">
+	<script src="../bootstrap.js">
 		$( "#spinner" ).spinner({
 			spin: function( event, ui ) {
 				if ( ui.value > 10 ) {
diff --git a/demos/spinner/time.html b/demos/spinner/time.html
index 5836784d155..c7ceb7116c9 100644
--- a/demos/spinner/time.html
+++ b/demos/spinner/time.html
@@ -7,7 +7,7 @@
 	<link rel="stylesheet" href="../../themes/base/all.css">
 	<link rel="stylesheet" href="../demos.css">
 	<script src="../../external/requirejs/require.js"></script>
-	<script src="../bootstrap.js" data-modules="external/globalize/globalize external/globalize/globalize.culture.de-DE external/jquery-mousewheel/jquery.mousewheel">
+	<script src="../bootstrap.js" data-modules="external/globalize/globalize external/globalize/globalize.culture.de-DE">
 		$.widget( "ui.timespinner", $.ui.spinner, {
 			options: {
 				// seconds
diff --git a/external/jquery-mousewheel/LICENSE.txt b/external/jquery-mousewheel/LICENSE.txt
deleted file mode 100644
index ad2020df4fc..00000000000
--- a/external/jquery-mousewheel/LICENSE.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2013, Brandon Aaron (http://brandon.aaron.sh)
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/external/jquery-mousewheel/jquery.mousewheel.js b/external/jquery-mousewheel/jquery.mousewheel.js
deleted file mode 100644
index 6756fa61088..00000000000
--- a/external/jquery-mousewheel/jquery.mousewheel.js
+++ /dev/null
@@ -1,221 +0,0 @@
-/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
- * Licensed under the MIT License (LICENSE.txt).
- *
- * Version: 3.1.12
- *
- * Requires: jQuery 1.2.2+
- */
-
-(function (factory) {
-    if ( typeof define === 'function' && define.amd ) {
-        // AMD. Register as an anonymous module.
-        define(['jquery'], factory);
-    } else if (typeof exports === 'object') {
-        // Node/CommonJS style for Browserify
-        module.exports = factory;
-    } else {
-        // Browser globals
-        factory(jQuery);
-    }
-}(function ($) {
-
-    var toFix  = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
-        toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
-                    ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
-        slice  = Array.prototype.slice,
-        nullLowestDeltaTimeout, lowestDelta;
-
-    if ( $.event.fixHooks ) {
-        for ( var i = toFix.length; i; ) {
-            $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
-        }
-    }
-
-    var special = $.event.special.mousewheel = {
-        version: '3.1.12',
-
-        setup: function() {
-            if ( this.addEventListener ) {
-                for ( var i = toBind.length; i; ) {
-                    this.addEventListener( toBind[--i], handler, false );
-                }
-            } else {
-                this.onmousewheel = handler;
-            }
-            // Store the line height and page height for this particular element
-            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
-            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
-        },
-
-        teardown: function() {
-            if ( this.removeEventListener ) {
-                for ( var i = toBind.length; i; ) {
-                    this.removeEventListener( toBind[--i], handler, false );
-                }
-            } else {
-                this.onmousewheel = null;
-            }
-            // Clean up the data we added to the element
-            $.removeData(this, 'mousewheel-line-height');
-            $.removeData(this, 'mousewheel-page-height');
-        },
-
-        getLineHeight: function(elem) {
-            var $elem = $(elem),
-                $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
-            if (!$parent.length) {
-                $parent = $('body');
-            }
-            return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
-        },
-
-        getPageHeight: function(elem) {
-            return $(elem).height();
-        },
-
-        settings: {
-            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
-            normalizeOffset: true  // calls getBoundingClientRect for each event
-        }
-    };
-
-    $.fn.extend({
-        mousewheel: function(fn) {
-            return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
-        },
-
-        unmousewheel: function(fn) {
-            return this.unbind('mousewheel', fn);
-        }
-    });
-
-
-    function handler(event) {
-        var orgEvent   = event || window.event,
-            args       = slice.call(arguments, 1),
-            delta      = 0,
-            deltaX     = 0,
-            deltaY     = 0,
-            absDelta   = 0,
-            offsetX    = 0,
-            offsetY    = 0;
-        event = $.event.fix(orgEvent);
-        event.type = 'mousewheel';
-
-        // Old school scrollwheel delta
-        if ( 'detail'      in orgEvent ) { deltaY = orgEvent.detail * -1;      }
-        if ( 'wheelDelta'  in orgEvent ) { deltaY = orgEvent.wheelDelta;       }
-        if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY;      }
-        if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
-
-        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
-        if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
-            deltaX = deltaY * -1;
-            deltaY = 0;
-        }
-
-        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
-        delta = deltaY === 0 ? deltaX : deltaY;
-
-        // New school wheel delta (wheel event)
-        if ( 'deltaY' in orgEvent ) {
-            deltaY = orgEvent.deltaY * -1;
-            delta  = deltaY;
-        }
-        if ( 'deltaX' in orgEvent ) {
-            deltaX = orgEvent.deltaX;
-            if ( deltaY === 0 ) { delta  = deltaX * -1; }
-        }
-
-        // No change actually happened, no reason to go any further
-        if ( deltaY === 0 && deltaX === 0 ) { return; }
-
-        // Need to convert lines and pages to pixels if we aren't already in pixels
-        // There are three delta modes:
-        //   * deltaMode 0 is by pixels, nothing to do
-        //   * deltaMode 1 is by lines
-        //   * deltaMode 2 is by pages
-        if ( orgEvent.deltaMode === 1 ) {
-            var lineHeight = $.data(this, 'mousewheel-line-height');
-            delta  *= lineHeight;
-            deltaY *= lineHeight;
-            deltaX *= lineHeight;
-        } else if ( orgEvent.deltaMode === 2 ) {
-            var pageHeight = $.data(this, 'mousewheel-page-height');
-            delta  *= pageHeight;
-            deltaY *= pageHeight;
-            deltaX *= pageHeight;
-        }
-
-        // Store lowest absolute delta to normalize the delta values
-        absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
-
-        if ( !lowestDelta || absDelta < lowestDelta ) {
-            lowestDelta = absDelta;
-
-            // Adjust older deltas if necessary
-            if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
-                lowestDelta /= 40;
-            }
-        }
-
-        // Adjust older deltas if necessary
-        if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
-            // Divide all the things by 40!
-            delta  /= 40;
-            deltaX /= 40;
-            deltaY /= 40;
-        }
-
-        // Get a whole, normalized value for the deltas
-        delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
-        deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
-        deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
-
-        // Normalise offsetX and offsetY properties
-        if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
-            var boundingRect = this.getBoundingClientRect();
-            offsetX = event.clientX - boundingRect.left;
-            offsetY = event.clientY - boundingRect.top;
-        }
-
-        // Add information to the event object
-        event.deltaX = deltaX;
-        event.deltaY = deltaY;
-        event.deltaFactor = lowestDelta;
-        event.offsetX = offsetX;
-        event.offsetY = offsetY;
-        // Go ahead and set deltaMode to 0 since we converted to pixels
-        // Although this is a little odd since we overwrite the deltaX/Y
-        // properties with normalized deltas.
-        event.deltaMode = 0;
-
-        // Add event and delta to the front of the arguments
-        args.unshift(event, delta, deltaX, deltaY);
-
-        // Clearout lowestDelta after sometime to better
-        // handle multiple device types that give different
-        // a different lowestDelta
-        // Ex: trackpad = 3 and mouse wheel = 120
-        if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
-        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
-
-        return ($.event.dispatch || $.event.handle).apply(this, args);
-    }
-
-    function nullLowestDelta() {
-        lowestDelta = null;
-    }
-
-    function shouldAdjustOldDeltas(orgEvent, absDelta) {
-        // If this is an older event and the delta is divisable by 120,
-        // then we are assuming that the browser is treating this as an
-        // older mouse wheel event and that we should divide the deltas
-        // by 40 to try and get a more usable deltaFactor.
-        // Side note, this actually impacts the reported scroll distance
-        // in older browsers and can cause scrolling to be slower than native.
-        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
-        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
-    }
-
-}));
diff --git a/tests/unit/spinner/core.js b/tests/unit/spinner/core.js
index e9f7bc3d218..befe439f6b3 100644
--- a/tests/unit/spinner/core.js
+++ b/tests/unit/spinner/core.js
@@ -163,7 +163,47 @@ QUnit.test( "mouse click on up button, increases value not greater than max", fu
 	assert.equal( element.val(), 0 );
 } );
 
-QUnit.test( "mousewheel on input", function( assert ) {
+QUnit.test( "wheel on input", function( assert ) {
+	var ready = assert.async();
+	assert.expect( 5 );
+
+	var element = $( "#spin" ).val( 0 ).spinner( {
+		step: 2
+	} );
+
+	element.simulate( "focus" );
+	setTimeout( step1 );
+
+	function getWheelEvent( deltaY ) {
+		return jQuery.Event( new WheelEvent( "wheel", { deltaY: deltaY } ) );
+	}
+
+	function step1() {
+		element.trigger( getWheelEvent() );
+		assert.equal( element.val(), 0, "wheel event without delta does not change value" );
+
+		element.trigger( getWheelEvent( -1 ) );
+		assert.equal( element.val(), 2, "delta -1" );
+
+		element.trigger( getWheelEvent( 0.2 ) );
+		assert.equal( element.val(), 0, "delta 0.2" );
+
+		element.trigger( getWheelEvent( 15 ) );
+		assert.equal( element.val(), -2, "delta 15" );
+
+		element.simulate( "blur" );
+		setTimeout( step2 );
+	}
+
+	function step2() {
+		element.trigger( "wheel", -1 );
+		assert.equal( element.val(), -2, "wheel when not focused" );
+
+		ready();
+	}
+} );
+
+QUnit.test( "mousewheel on input (DEPRECATED)", function( assert ) {
 	var ready = assert.async();
 	assert.expect( 5 );
 
diff --git a/ui/widgets/spinner.js b/ui/widgets/spinner.js
index d999d85d783..4fb41d7bb65 100644
--- a/ui/widgets/spinner.js
+++ b/ui/widgets/spinner.js
@@ -136,9 +136,10 @@ $.widget( "ui.spinner", {
 				this._trigger( "change", event );
 			}
 		},
-		mousewheel: function( event, delta ) {
+		wheel: function( event ) {
 			var activeElement = this.document[ 0 ].activeElement;
 			var isActive = this.element[ 0 ] === activeElement;
+			var delta = event.deltaY || event.originalEvent && event.originalEvent.deltaY;
 
 			if ( !isActive || !delta ) {
 				return;
@@ -148,7 +149,7 @@ $.widget( "ui.spinner", {
 				return false;
 			}
 
-			this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
+			this._spin( ( delta > 0 ? -1 : 1 ) * this.options.step, event );
 			clearTimeout( this.mousewheelTimer );
 			this.mousewheelTimer = this._delay( function() {
 				if ( this.spinning ) {
@@ -157,6 +158,20 @@ $.widget( "ui.spinner", {
 			}, 100 );
 			event.preventDefault();
 		},
+
+		// DEPRECATED
+		// Kept for backwards compatibility. Please use the modern `wheel`
+		// event. The `delta` parameter is provided by the jQuery Mousewheel
+		// plugin if one is loaded.
+		mousewheel: function( event, delta ) {
+			var wheelEvent = $.Event( event );
+			wheelEvent.type = "wheel";
+			if ( delta ) {
+				wheelEvent.deltaY = -delta;
+			}
+			return this._events.wheel.call( this, wheelEvent );
+		},
+
 		"mousedown .ui-spinner-button": function( event ) {
 			var previous;