Disable scrolling on `<input type=number>` in React
Asked Answered
C

11

48

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.

Chabazite answered 3/8, 2020 at 6:3 Comment(5)
Did you tried doing e.preventDefault() for that field ?Melon
yes I've tried, even I tried to write code in public/index.html to remove mousewheel event in javascript (outside of react), but it didn't work. may be I did some mistakeChabazite
Check this , it is plain JS and HTML codepen.io/ahastudio/pen/eVovMvTeheran
I have tried this - <input type="number" className = "myClass" onWheel = {(e) => this.getWheel(e)}></input> and inside the getWheel method - e.target.blur(); Kindly try this once.Melon
@Teheran this solution codepen.io/ahastudio/pen/eVovMv is for jQuery but not for ReactJsChabazite
L
8

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.

Lysin answered 31/10, 2022 at 14:4 Comment(0)
P
63

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.

Peisch answered 7/5, 2021 at 9:8 Comment(2)
For TypeScript you will need to cast it to the HTMLElement type... (e.target as HTMLElement).blur();Quicklime
Try e.target instanceof HTMLElement as a safe alternative in TypeScript. See github.com/Microsoft/TypeScript/issues/…Forsake
C
29

You can blur the field on onWheel handler. Something like this

<input type='number' onWheel={ event => event.currentTarget.blur() } />
C answered 19/4, 2021 at 7:1 Comment(1)
This solution solve the TS problem using `<input type='number' onWheel={ event => event.target.blur() } />Solicitor
L
8

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.

Lysin answered 31/10, 2022 at 14:4 Comment(0)
K
3

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.

Kettledrummer answered 4/6, 2021 at 16:30 Comment(1)
In React 17.0.2 I see an error saying you can't preventDefault on a passive event listenerSacrum
B
3

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.

Beadledom answered 14/10, 2021 at 14:49 Comment(0)
E
1

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;

codesandbox here

Extravagate answered 3/8, 2020 at 6:39 Comment(3)
Thanks @Extravagate for above code, This worked fine but due to blur() method it is not user friendly. As I roll mouse wheel it looses focus and for input I have to click again in the input field to add a number.Chabazite
Look at this fiddle, this experience is really nice and smooth, jsfiddle.net/x6o7dzuvChabazite
Add this to onWheel function setTimeout(() => this.inputRef.current.focus(), 100);Extravagate
N
1
Prevent onWheel's event

docs

event blur

example in react


const inputElem = useRef();

onWheel={e=> {
  e.preventDefault();
  inputElem.current.blur();
 } 
}
  • in react code
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>
  );
}

Nuristan answered 19/5, 2023 at 6:8 Comment(6)
Does not work in Firefox, I can still change the number with the scroll wheel in the provided sandboxMica
it is working well on mine. mac firebox browser. are you using windows?Nuristan
I am using Firefox 113.0.1 (64-bit) on UbuntuMica
Tried Chromium 113.0.5672.126 too, it is also not working thereMica
I've updated the codesandbox and answer as well, pls try and check it out. I hope it is working welllll. ThanksNuristan
Now it works, but the solution repeats this answer and this answer, which both use blur to remove the focus from the input before the scroll happens.Mica
D
1

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

Decile answered 19/1 at 7:53 Comment(0)
H
0

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;
Huron answered 5/7, 2023 at 7:39 Comment(0)
M
0

you can use attribute onWheel like this:

onWheel={(e) => e.currentTarget.blur()}
Misdirection answered 21/11, 2023 at 21:56 Comment(0)
P
-3

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; 
}
Philtre answered 15/6, 2022 at 9:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.