Is it possible to disable the scroll wheel changing the number in an input number field?
I've messed with webkit-specific CSS to remove the spinner but I'd like to get rid of this behavior altogether. I like using type=number
since it brings up a nice keyboard on iOS.

- 1,475
- 11
- 13

- 5,758
- 8
- 34
- 49
-
8use input type tel (type="tel") instead of using type=number. It will popup a iOS num keyboard. – Praveen Vijayan Mar 15 '12 at 00:49
-
1What happens when you add an `onscroll` handler with just `event.preventDefault()` in it? – robertc Mar 15 '12 at 01:25
-
47In my humble opinion, I don't even think this should be a feature. If I had any say in browser development I would probably push to remove this feature. It's nothing but annoying, and I don't know anyone who would actually use it. – Kirkland Oct 30 '14 at 14:17
-
8I totally agree with you Kirkland. It's just bad UX to be scrolling a page with a form and, when a number input element goes under your mouse, it starts incrementing and the page stops scrolling. Totally disorienting. – kjs3 Oct 31 '14 at 14:55
-
6@PraveenVijayan: Alrhough this is a workaround, it goes against any reason for using the new html5 input types. In future it can be that phones will give you possibility to pick number from contacts or anything, which will look very strange if you meant this to be a different kind of number. – awe Mar 03 '15 at 12:48
-
I solved this with the following code sample "" It is very annoying when that scroll bar comes up for a mobile number input – Priyom saha Jun 19 '21 at 04:35
-
In React ```onWheel={e => e.target.blur()}``` is the easiest solution. – iku Oct 18 '22 at 05:22
23 Answers
Prevent the default behavior of the mousewheel event on input-number elements like suggested by others (calling "blur()" would normally not be the preferred way to do it, because that wouldn't be, what the user wants).
BUT. I would avoid listening for the mousewheel event on all input-number elements all the time and only do it, when the element is in focus (that's when the problem exists). Otherwise the user cannot scroll the page when the mouse pointer is anywhere over a input-number element.
Solution for jQuery:
// disable mousewheel on a input number field when in focus
// (to prevent Chromium browsers change the value when scrolling)
$('form').on('focus', 'input[type=number]', function (e) {
$(this).on('wheel.disableScroll', function (e) {
e.preventDefault()
})
})
$('form').on('blur', 'input[type=number]', function (e) {
$(this).off('wheel.disableScroll')
})
(Delegate focus events to the surrounding form element - to avoid to many event listeners, which are bad for performance.)
-
2Great answer. I think if I were doing this today I would use Modernizr.touch to conditionally apply the event listener on non-touch devices. Basically what user2863715 said below. – kjs3 Jan 17 '14 at 16:21
-
Great answer, but at least in webkit, this also prevents the window from scrolling while the cursor is over the input element. I thought mousewheel events are supposed to bubble too. – Ryan McGeary Oct 08 '14 at 20:21
-
When only applying the disable scroll function to an element when it is in focus, this should not prevent scrolling, when the mouse is over the input element. But it prevents from scrolling the window, when the element is in focus. And yes, why are the mousewheel event not bubbling ... :/ – Grantzau Oct 10 '14 at 08:34
-
20This is a nice fix to a behaviour that shouldn't exist in the first place. – Jonny Jun 19 '15 at 19:06
-
This doesn't work on most unix type platform gnome, osx, android (with mouse) as scroll behaviour does not require the input to be focused. Alternatively, I just used the text type of inputs and put my number restriction to it (lossing up/down key shortcut but can be added with js as well) – zeachco Jul 14 '15 at 02:23
-
@zeachco when I am using Chrome/OSX the input does not scroll unless it is focused. – Grantzau Aug 17 '15 at 09:18
-
You're right, that behaviour doesn't affect osx anymore (tested yosemite just now). AFAIR kde had that behaviour and gnome2/3 is still doing it on linux but it's a very small percentage of the clients using it. As for Android, been a while i tested it with a mouse ^_^ – zeachco Aug 18 '15 at 14:47
-
-
1What is the "wheel.disableScroll" event and how is it unique and different from the event "wheel"? I can't find info on the "disableScroll" portion of this event online. – Art Geigel May 11 '20 at 09:16
-
Nice, but better use $(document).on event instead $('form') becouce $('form') event not work when you create form dynamically. – stefo91 Oct 16 '20 at 07:49
-
For anyone looking at for a vanilla JS in 2021, look at @peter-rakmanyi 's solution https://stackoverflow.com/a/38589039/2942765 – sgarcia.dev Aug 27 '21 at 15:16
One event listener to rule them all
This is similar to @Simon Perepelitsa's answer in pure js, but a bit simpler, as it puts one event listener on the document element for all inputs and checks if the focused element is a number input tpye:
document.addEventListener("wheel", function(event){
if(document.activeElement.type === "number"){
document.activeElement.blur();
}
});
If you want to turn off the value scrolling behaviour on some fields by class/id, but not others just add &&
and the corresponding document selector instead:
document.addEventListener("wheel", function(event){
if(document.activeElement.type === "number" &&
document.activeElement.classList.contains("noscroll"))
{
document.activeElement.blur();
}
});
with this:
<input type="number" class="noscroll"/>
If an input has the noscroll class it wont change on scroll, otherwise everything stays the same.
Test here with JSFiddle

- 19,086
- 22
- 87
- 167

- 1,475
- 11
- 13
-
I see this has been downvoted. If you see a problem please leave a comment as well with the downvote. If I missed something I would like to learn what it is. Thanks. – Peter Rakmanyi Nov 19 '19 at 15:01
-
5For modern browser, please use event `wheel` instead of `mousewheel`. Reference: https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event PS. I'm not the one who down vote. – vee Jan 19 '20 at 09:08
-
A minor problem with this one is that the script will run on every single mouse wheel event from every element. If for some reason there is a custom element with a "number" prop that is not an input, it will also run and cause a hard to debug problem. – wkrueger Aug 02 '23 at 23:00
-
@wkrueger "number" is the input type as in ``, not a prop as in `
`. Also it exits as soon as possible if conditions are not met. The idea is to not have a lot of listeners and also work when elements get dynamically added and removed. Any suggestions to improve it are welcome. – Peter Rakmanyi Aug 03 '23 at 17:21
$(document).on("wheel", "input[type=number]", function (e) {
$(this).blur();
});

- 6,835
- 2
- 48
- 59
-
3
-
1This fails on Google Chrome if you select the item and then scroll. The value is still changed by a small amount. – eKKiM May 17 '21 at 11:44
You can simply use the HTML onwheel attribute.
This option have no effects on scrolling over other elements of the page.
And add a listener for all inputs don't work in inputs dynamically created posteriorly.
Aditionaly, you can remove the input arrows with CSS.
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type="number"] {
-moz-appearance: textfield;
}
<input type="number" onwheel="this.blur()" />

- 669
- 7
- 5
-
1
-
1source: https://css-tricks.com/snippets/css/turn-off-number-input-spinners/ – Hafiz Temuri Aug 17 '18 at 19:06
-
1We can find this CSS in many sources. Anyway, the CSS is only a bonus. The real solution to the question is the HTML onwheel attribute. ;-) – Maikon Matheus Aug 18 '18 at 20:08
-
6I like this solution! Thanks. In my case, the `onBlur()` was not as expected. I setup up a simple `return false` instead to really "do nothing on wheel". `` – Donni Oct 26 '18 at 13:13
I have an alternative suggestion. The problem I see with most of the common recommendation of firing a blur event is that it has unexpected side-effects. It's not always a good thing to remove a focus state unexpectedly.
Why not this instead?
<input type="number" onwheel="return false;" />
It's very simple and straight-forward, easy to implement, and no side-effects that I can think of.

- 601
- 4
- 6
-
3
-
1This works, but the downside is scrolling doesn't work at all when hovering over a focussed number input. – mckeed Nov 23 '21 at 16:02
-
@mckeed I'm not sure I understand. Isn't that the intention? The OP wanted to prevent scrolling from changing the input value. – Austin Gil Nov 24 '21 at 19:09
-
Works well, except when scrolling down a page with number fields on it and the mouse just so happens to go over a number field. It interrupts the scroll. (Only tested with FF) – MeSo2 Dec 16 '21 at 07:01
-
1@MeSo2, that is an excellent point. Changing native browser behavior is a big downside. To be honest, it's almost always better to just use type="text" Lol. – Austin Gil Dec 17 '21 at 16:16
-
6For React / Next.js, I used this `onWheel={e => e.target.blur()}` I'm not sure why Mac does not provide an option to disable it. – Surjith S M Jan 19 '22 at 13:27
-
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })
For jQuery example and a cross-browser solution see related question:

- 1
- 1

- 20,350
- 8
- 55
- 74
-
2Thanks Seymon, I managed to do it for all number input with jQuery this way : `$(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); });` I used blur instead of prevent default so it doesn't block the page from scrolling ! – Thibaut Colson Feb 11 '13 at 13:21
-
Nice addition about blur, I didn't know you can still allow page scrolling. I've updated my answer. – Simon Perepelitsa Feb 11 '13 at 18:07
-
13FYI, `live()` is deprecated. Now, you should use `on()`: `$(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });` – Saeid Oct 11 '13 at 18:38
-
3
-
For modern browser, please use event `wheel` instead of `mousewheel`. Reference: https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event – vee Jan 19 '20 at 09:07
ReactJS Solution
For those needing a React solution, here's an onWheel
handler for your type="number"
input to prevent the number from changing and prevent the page from scrolling while the user tries to wheel over the input. Finally, it'll refocus on the input so the user can keep editing as intended:
const numberInputOnWheelPreventChange = (e) => {
// Prevent the input value change
e.target.blur()
// Prevent the page/container scrolling
e.stopPropagation()
// Refocus immediately, on the next tick (after the current function is done)
setTimeout(() => {
e.target.focus()
}, 0)
}
return <input type="number" onWheel={numberInputOnWheelPreventChange}/>

- 1,001
- 1
- 16
- 16
-
1
-
This is great, except I removed `e.stopPropagation()` so users can scroll the page as expected. – Theodore Brown Apr 18 '23 at 21:10
-
@TheodoreBrown I don't think users are expecting to scroll the page when they're wheeling through an input. But that is definitely a UX choice for your team to make. – lwdthe1 May 17 '23 at 00:27
-
@lwdthe1 If users roll their scroll wheel, I think they are expecting the page to scroll, just like it does when the cursor is over other input types that don't change value. – Theodore Brown May 17 '23 at 18:07
-
@TheodoreBrown Sure, but I've personally experienced the opposite desire. It's a UX choice that should be considered by every team. For your users, you don't want scroll. That doesn't mean the alternative is wrong – lwdthe1 May 17 '23 at 22:27
@Semyon Perepelitsa
There is a better solution for this. Blur removes the focus from the input and that is a side affect that you do not want. You should use evt.preventDefault instead. This prevents the default behavior of the input when the user scrolls. Here is the code:
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(evt){ evt.preventDefault(); })

- 1,435
- 16
- 24
-
9It works, but the event won't bubble, so the page will not scroll. Is there a way to keep default behavior (page scroll) without bluring? – GuiGS Aug 30 '14 at 23:30
-
1For modern browser, please use event `wheel` instead of `mousewheel`. Reference: https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event – vee Jan 19 '20 at 09:07
For anyone working with React and looking for solution. I’ve found out that easiest way is to use onWheelCapture prop in Input component like this:
onWheelCapture={e => {
e.target.blur()
}}

- 195
- 1
- 3
- 9
-
1`target` doesn't have `blur()`, so I had to use `e.currentTarget.blur()` to make it work. – M. Lee May 18 '22 at 19:10
First you must stop the mousewheel event by either:
- Disabling it with
mousewheel.disableScroll
- Intercepting it with
e.preventDefault();
- By removing focus from the element
el.blur();
The first two approaches both stop the window from scrolling and the last removes focus from the element; both of which are undesirable outcomes.
One workaround is to use el.blur()
and refocus the element after a delay:
$('input[type=number]').on('mousewheel', function(){
var el = $(this);
el.blur();
setTimeout(function(){
el.focus();
}, 10);
});

- 1,955
- 1
- 18
- 16
-
3A good looking solution, but in testing I found that this solution had the side effect of stealing focus. I tweaked this to have: a test to see if the element had focus: `var hadFocus = el.is(':focus');` before blurring, and then a guard to only set the timeout if hadFocs was true. – Rob Dawson Apr 25 '17 at 22:14
Easiest solution is to add onWheel={ event => event.currentTarget.blur() }}
on input itself.

- 1,231
- 15
- 29
Typescript Variation
Typescript needs to know that you're working with an HTMLElement for type safety, else you'll see lots of Property 'type' does not exist on type 'Element'
type of errors.
document.addEventListener("wheel", function(event){
const numberInput = (<HTMLInputElement>document.activeElement);
if (numberInput.type === "number") {
numberInput.blur();
}
});
In my case, I needed to maintain focus and still apply the scroll. None of the solutions above can handle that and doing blur/focus feels a bit hacky to me.
This maintains existing focus and also keeps the scroll. You know... like the browser should. Only minimally tested in chrome and only supports Y-axis.
// you could make this target a specific input instead of document
document.addEventListener('wheel', event => {
if (!event.target) return;
const isNumberInput = event.target.nodeName === 'INPUT' && event.target.type === 'number';
const isFocused = event.target === document.activeElement;
if (isNumberInput && isFocused) {
// prevent stupid input change
event.preventDefault();
// since we're taking over scrolling, we want to make sure
// nothing else gets the event
event.stopPropagation();
// finally we reapply the scroll
applyScroll(event);
}
}, { passive: false });
// this walks up the tree for event.target to find the first
// scrollable parent. this is probably good enough for most situations.
const applyScroll = event => {
try {
// console.debug('attempting to reapply scroll. searching for scrollable container...');
let scrollContainer = event.target;
while (scrollContainer && scrollContainer !== document.body && !elementIsScrollable(scrollContainer)) {
scrollContainer = scrollContainer.parentElement;
// console.debug('\t-> container was not scrollable. checking parent', scrollContainer);
}
if (scrollContainer) {
// console.debug('scrollContainer container found. applying scroll', scrollContainer, event.deltaY);
scrollContainer.scrollBy({ top: event.deltaY });
}
else {
// console.debug('no scrollContainer found');
}
}
catch (err) {
console.info('failed to reapply scroll', err, event);
}
};
const elementIsScrollable = element => {
const { scrollHeight = 0, offsetHeight = 0 } = element;
const scrollable = style.overflowY === 'auto' || style.overflowY === 'scroll';
return scrollable && scrollHeight > 0 && offsetHeight > 0 && element.scrollHeight > element.offsetHeight;
};

- 1,583
- 18
- 22
The provided answers do not work in Firefox (Quantum). The event listener needs to be changed from mousewheel to wheel:
$(':input[type=number]').on('wheel',function(e){ $(this).blur(); });
This code works on Firefox Quantum and Chrome.

- 95
- 8
While trying to solve this for myself, I noticed that it's actually possible to retain the scrolling of the page and focus of the input while disabling number changes by attempting to re-fire the caught event on the parent element of the <input type="number"/>
on which it was caught, simply like this:
e.target.parentElement.dispatchEvent(e);
However, this causes an error in browser console, and is probably not guaranteed to work everywhere (I only tested on Firefox), since it is intentionally invalid code.
Another solution which works nicely at least on Firefox and Chromium is to temporarily make the <input>
element readOnly
, like this:
function handleScroll(e) {
if (e.target.tagName.toLowerCase() === 'input'
&& (e.target.type === 'number')
&& (e.target === document.activeElement)
&& !e.target.readOnly
) {
e.target.readOnly = true;
setTimeout(function(el){ el.readOnly = false; }, 0, e.target);
}
}
document.addEventListener('wheel', function(e){ handleScroll(e); });
One side effect that I've noticed is that it may cause the field to flicker for a split-second if you have different styling for readOnly
fields, but for my case at least, this doesn't seem to be an issue.
Similarly, (as explained in James' answer) instead of modifying the readOnly
property, you can blur()
the field and then focus()
it back, but again, depending on styles in use, some flickering might occur.
Alternatively, as mentioned in other comments here, you can just call preventDefault()
on the event instead. Assuming that you only handle wheel
events on number inputs which are in focus and under the mouse cursor (that's what the three conditions above signify), negative impact on user experience would be close to none.

- 555
- 3
- 12
If you want a solution that doesn’t need JavaScript, combining some HTML functionality with a CSS pseudo-element does the trick:
span {
position: relative;
display: inline-block; /* Fit around contents */
}
span::after {
content: "";
position: absolute;
top: 0; right: 0; bottom: 0; left: 0; /* Stretch over containing block */
cursor: text; /* restore I-beam cursor */
}
/* Restore context menu while editing */
input:focus {
position: relative;
z-index: 1;
}
<label>How many javascripts can u fit in u mouth?
<span><input type="number" min="0" max="99" value="1"></span>
</label>
This works because clicking on the contents of a <label>
that’s associated with a form field will focus the field. However, the “windowpane” of the pseudo-element over the field will block mousewheel events from reaching it.
The drawback is that the up/down spinner buttons no longer work, but you said you had removed those anyway.
In theory, one could restore the context menu without requiring the input to be focused first: :hover
styles shouldn’t fire when the user scrolls, since browsers avoid recalculating them during scrolling for performance reasons, but I haven’t thoroughly cross-browser/device tested it.

- 1,330
- 2
- 19
- 40
-
This does not work. Open FireFox. Focus on the input. Without mouse on still on the input start scrolling. Observe the unwanted behavior – Dmitry Efimenko Dec 16 '22 at 00:01
Non-JS solution
I like using type=number since it brings up a nice keyboard on iOS.
The keyboard is nice indeed. But we can get the same behaviour with:
<input inputmode="numeric" pattern="[0-9]*" />
Taken from gov.uk which was linked in the MUI docs. Works nicely for our product.
Grain of salt
Please check browser support for inputmode
. Most mobile browsers are supported, and to me inputmode
is mostly about the mobile experience. But YMMV.

- 3,224
- 1
- 29
- 41
function fixNumericScrolling() {
$$( "input[type=number]" ).addEvent( "mousewheel", function(e) {
stopAll(e);
} );
}
function stopAll(e) {
if( typeof( e.preventDefault ) != "undefined" ) e.preventDefault();
if( typeof( e.stopImmediatePropagation ) != "undefined" ) e.stopImmediatePropagation();
if( typeof( event ) != "undefined" ) {
if( typeof( event.preventDefault ) != "undefined" ) event.preventDefault();
if( typeof( event.stopImmediatePropagation ) != "undefined" ) event.stopImmediatePropagation();
}
return false;
}

- 369
- 2
- 5
Most answers blur the number element even if the cursor isn't hovering over it; the below does not
document.addEventListener("wheel", function(event) {
if (document.activeElement.type === "number" &&
document.elementFromPoint(event.x, event.y) == document.activeElement) {
document.activeElement.blur();
}
});

- 324
- 2
- 7
I was struggling with the solution. So, This and other posts help me to do this. We need to change some stuff regarding the best answer here. So in order to disable scrolling, we must add the following:
<script>
$(document).ready(function() {
$('input[type=number]').on('wheel',function(e){ $(this).blur(); });
});
</script>
Instead of using "onwheel" we use "wheel" :)

- 81
- 2
- 7
Antd / React + Typescript answer
const myComponent = () => {
const inputRef: React.RefObject<HTMLInputElement> = createRef();
return <Input
ref={inputRef}
type="number"
onWheel={(e) => {
if (inputRef && inputRef.current && inputRef.current.blur) {
inputRef.current.blur();
}
e.preventDefault();
}}
/>
}

- 424
- 3
- 5
Angular solution. One directive to rule them all!
In contrast to other solutions, with this solution the user
- does not loose focus on the input
- and still able to scroll!
import { Directive, ElementRef, NgZone, OnDestroy } from '@angular/core';
import { fromEvent, Subscription, takeUntil } from 'rxjs';
import { tap, switchMap } from 'rxjs/operators';
@Directive({
selector: 'input[type=number]',
})
export class FixNumberInputScrollDirective implements OnDestroy {
private subs = new Subscription();
constructor(elRef: ElementRef<HTMLInputElement>, zone: NgZone) {
const el = elRef.nativeElement;
const focus$ = fromEvent(el, 'focus');
const blur$ = fromEvent(el, 'blur');
// when input is focused, start listening to the scroll of element. On this event blur and
// re-focus on the next tick. This allows for the page scroll to still happen, but the unwanted
// input number change is prevented.
// Stop listening to the scroll when focus is lost
const preventWheel$ = focus$.pipe(
switchMap(() => {
return fromEvent(el, 'wheel', { passive: false }).pipe(
tap(() => {
zone.runOutsideAngular(() => {
el.blur();
setTimeout(() => {
el.focus();
}, 0);
})
}),
takeUntil(blur$)
);
})
);
this.subs.add(preventWheel$.subscribe());
}
ngOnDestroy() {
this.subs.unsubscribe();
}
}

- 10,973
- 7
- 62
- 79
const disableNumberInputChangeOnMouseScroll = (): void => {
let currentFocus: EventTarget | null = null;
document.addEventListener("focusin", (event) => {
currentFocus = event.target;
});
document.addEventListener("wheel", (_event) => {
const activeElement = document.activeElement;
if (activeElement?.tagName === "INPUT" && (activeElement as HTMLInputElement).type === "number") {
const numberInput = activeElement as HTMLInputElement;
// blur removes focus from the input, preventing the scroll from changing the value.
numberInput.blur();
if (currentFocus === numberInput) {
// but at the same time, if the caret (https://en.wikipedia.org/wiki/Caret_navigation) was in the input,
// we want to make sure the focus is restored.
window.setTimeout(() => numberInput.focus({ preventScroll: true }), 1);
}
}
});
};
Number input does not change on scroll, but at the same time, an user does not lose focus if the caret is in the input.

- 3,697
- 1
- 11
- 20