javascriptreactjsscrollhorizontal-scrollingmousewheel

Horizontal Scrolling on React Component Using Vertical Mouse Wheel


I have a component that resizes into a horizontal row of bootstrap cards when in a smaller desktop window. For users without a horizontal mouse wheel and not using a touchpad, I would like to allow users to scroll horizontally using their vertical mouse wheel movements when hovering over this particular component.

Here is the original StackOverflow issue I based my code off of: https://stackoverflow.com/a/15343916/8387497

Horizontal Scroll helper component:

function horizontalScroll (event) {
  const delta = Math.max(-1, Math.min(1, (event.nativeEvent.wheelDelta || -event.nativeEvent.detail)))
  event.currentTarget.scrollLeft -= (delta * 10)
  event.preventDefault
}

How I've implemented it on component requiring horizontal scrolling:

<Row className='announcements-home' onWheel={horizontalScroll} >

When I've placed this horizontalScroll helper function within the React onWheel event, it scrolls horizontally AND vertically. My desired outcome is just horizontal scrolling. Also, Firefox does not appear to respond at all to horizontal scrolling with these changes.


Solution

  • Okay, so the issue seems to be that you only refer to the function event.preventDefault rather than invoking it. Adding some brackets at the end to invoke it should do the trick: event.preventDefault().

    I however found this issue while looking for some simple code to use, so I will also leave the hook I made for this if others in the same situation:

    import { useRef, useEffect } from "react";
    
    export function useHorizontalScroll() {
      const elRef = useRef();
      useEffect(() => {
        const el = elRef.current;
        if (el) {
          const onWheel = e => {
            if (e.deltaY == 0) return;
            e.preventDefault();
            el.scrollTo({
              left: el.scrollLeft + e.deltaY,
              behavior: "smooth"
            });
          };
          el.addEventListener("wheel", onWheel);
          return () => el.removeEventListener("wheel", onWheel);
        }
      }, []);
      return elRef;
    }
    

    Usage:

    import React from "react";
    import { useSideScroll } from "./useSideScroll";
    
    export const SideScrollTest = () => {
      const scrollRef = useHorizontalScroll();
      return (
        <div ref={scrollRef} style={{ width: 300, overflow: "auto" }}>
          <div style={{ whiteSpace: "nowrap" }}>
            I will definitely overflow due to the small width of my parent container
          </div>
        </div>
      );
    };
    

    Note: The scroll behavior "smooth" seems to be giving some trouble when trying to do continuous scrolling. This behavior can be omitted to have proper continuous scrolling, but it will look jerky.

    As far as I know, there is no easy solution for this. I have however created a rather involved solution in my own project, so thought some people may appreciate that also: https://gist.github.com/TarVK/4cc89772e606e57f268d479605d7aded