Reputation: 866
This question was asked before but provided solution is just for jQuery
, as I'm facing same problem in ReactJs.
Is it possible to disable the scroll wheel changing the number in an input number field? I removed spinner arrows using CSS but mouse wheel still working and messing the functionality.
I want input type number
because it gives numeric keyboard on mobile/touch devices.
Upvotes: 51
Views: 57526
Reputation: 1
<input
id={id}
type="number"
// onFocus={(e) => { e.target.addEventListener('wheel', (wheelEvent) =>{ passive: false })}} // allows - numbers change on scroll & prevent page scroll while hovering & changing numbers with scroll
onFocus={(e) => e.target.addEventListener('wheel', (e) => e.preventDefault(), { passive: false })} // dosent allow - numbers change on scroll
onWheel={(event) => window.scrollBy(0, event.deltaY)} // allows scrolling, cause preventDefault stops scrolling when hovered on input.
{...inputProps}
/>
Upvotes: 0
Reputation: 297
Full Typescript React solution:
import { WheelEvent } from 'react';
<input onWheel={(e: WheelEvent<HTMLInputElement>) => e.currentTarget.blur()} />
Upvotes: 0
Reputation: 11
onWheel={(event) => event.currentTarget.blur()}
plays well with typescript. event.target
is not guaranteed to be the input element event listener attached to.
Upvotes: 1
Reputation: 9
It is not a native behavior of html input. Try to look for mousewheel
listeners in your page. It should be some of imported libraries that add this changing by scrolling.
You can see that there is no changing by scrolling by default - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number
Upvotes: 0
Reputation: 1219
Another very simple way of achieving this, if you don't care about the controls either, is by putting the step property to 0.
<input type="number" step={0} />
and use CSS to hide the controls: https://www.w3schools.com/howto/howto_css_hide_arrow_number.asp
Upvotes: 1
Reputation: 196
you can use attribute onWheel like this:
onWheel={(e) => e.currentTarget.blur()}
Upvotes: 0
Reputation: 1
If you want to remove this scroll feature from all the number input fields of your project as whole or alternatively you could only import it into your component and this is the solution that worked for me.
First you create a custom hook like this one in your desired location in your project.
import { useEffect } from 'react';
const DisableNumInputScroll = () => {
const handleWheel = (event) => {
const { type } = event.target;
if(type === 'number'){
event.preventDefault();
}
}
useEffect(() => {
document.addEventListener('wheel', handleWheel, { passive: false });
return () => {
document.removeEventListener('wheel', handleWheel);
};
}, []);
return null;
};
export default DisableNumInputScroll;
Basically this adds a wheel event listener to the document and when the event occurs, it is checked if target of that event element is of type number. If yes, it will stop the default behavior which is responsible for the scroll increasing the number in input tag.
You can use this custom hook in your main App.js file like so,
import DisableNumInputScroll from './DisableNumInputScroll';
const App = () => {
return (
<>
<DisableNumInputScroll />
{/* Rest of your application */}
</>
);
};
export default App;
Upvotes: 0
Reputation: 373
const inputElem = useRef();
onWheel={e=> {
e.preventDefault();
inputElem.current.blur();
}
}
import { useRef } from "react";
import "./styles.css";
export default function App() {
const inputElem = useRef();
const handleOnWheel = (e) => {
// if not use preventDefault, it is working
e.preventDefault();
// The blur event fires when an element has lost focus. The event does not bubble,
inputElem.current.blur();
};
return (
<div className="App">
<form>
<input
ref={inputElem}
type="number"
placeholder="type num"
// prevent scroll on number input
onWheel={handleOnWheel}
/>
<button type="submit">send</button>
</form>
</div>
);
}
Upvotes: 1
Reputation: 116
I had the same problem, except I was working on desktop version only. To blur the focus on the input as suggested in other answers works to stop the scrolling. But it wasn't what I wanted. I still want the user to be able to change the input with the keyboard.
So to disable scrolling on <input type=number>
in React I added an onFocus
property as follows:
<input
//...some input properties...//
type="number"
onFocus={(e) => e.target.addEventListener("wheel", function (e) { e.preventDefault() }, { passive: false })}
/>
It worked fine for me. I hope it helps others.
Upvotes: 10
Reputation: 1
this can also be achieved using css.
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button
{
-webkit-appearance: none;
margin: 0;
}
Upvotes: -4
Reputation: 2566
Simplest answer:
<input type="number" onWheel={(e) => e.target.blur()} />
e
is short for event
.
This also works:
<input type="number" onWheel={() => document.activeElement.blur()} />
Either of these can be used either in a functional or in a class component.
Upvotes: 66
Reputation: 31
I don't think this is the best solution if you only want a numeric keyboard since there is a property that actually let you set whatever keyboard type you want, e.g. inputMode="numeric"
Changing global events is not good practice and neither is blurring out of the field.
Upvotes: 3
Reputation: 221
I solved this using a functional component that wraps the input
element and adds an event listener for "wheel"
and prevents default behavior. I find this preferable to using blur()
which may have undesirable UX.
// Simply a wrapper for <input type="number"/> that disables scrolling to increment
import { useEffect, useRef } from "react";
export const NumberInput = (props) => {
const quantityInputRef = useRef(null);
useEffect(() => {
const ignoreScroll = (e) => {
e.preventDefault();
};
quantityInputRef.current && quantityInputRef.current.addEventListener("wheel", ignoreScroll);
}, [quantityInputRef]);
return <input ref={quantityInputRef} type="number" {...props} />;
};
In production, I actually use this component to disable scroll-incrementing for the <TextField>
component from material-ui instead of <input>
. I've used the native input in my example because that's what the question was asking about.
Upvotes: 4
Reputation: 1149
You can blur the field on onWheel handler. Something like this
<input type='number' onWheel={ event => event.currentTarget.blur() } />
Upvotes: 30
Reputation: 426
In react version you should use ref. Take a look at the example below :
import React, { Component, createRef } from "react";
class MyInput extends Component {
constructor(props) {
super(props);
this.inputRef = createRef();
}
onWheel = () => {
this.inputRef.current.blur();
};
render() {
return (
<div>
My input number :
<input type="number" ref={this.inputRef} onWheel={this.onWheel} />
</div>
);
}
}
export default MyInput;
Upvotes: 2