6

I have used tailwind-CSS on react js I want to scroll horizontally using mouse wheel when user hover over the card section so for pc users can scroll horizontally by using mouse wheel instead of both shift and mouse wheel. Live Anywhere

        <div className="flex space-x-3 overflow-y-scroll scrollbar-hide p-3 -ml-3">
          {cardsDate?.map(({ img, title }) => (
            <MediumCard key={img} img={img} title={title} /> 
          ))}
        </div>
    </section>

enter image description here

4 Answers 4

15

You can use a custom scroll function as a ref to your div.

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;
}

The above function can be imported and used as follows:

    <div className="App" ref={scrollRef} style={{ overflow: "auto" }}>
      <div style={{ whiteSpace: "nowrap" }}>
        <Picture />
      </div>
    </div>

I created a codesandbox as an example.

Sign up to request clarification or add additional context in comments.

Comments

3

The version of hd3adcode is perfect. Here the typescript version :

export function useHorizontalScroll<T extends HTMLElement>() {
  const elRef = useRef<T>(null);
  useEffect(() => {
    const el = elRef.current;
    if (el) {
      const onWheel = (e: WheelEvent) => {
        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;
}

Comments

2

try with scrollBy working well

const element = document.querySelector("#container");

element.addEventListener('wheel', (event) => {
  event.preventDefault();

  element.scrollBy({
    left: event.deltaY < 0 ? -30 : 30,
    
  });
});

container with his children elements

2 Comments

For some reason your solution seems to perform better, the one proposed by hd3adcode is kinda glitchy, seems to run slower, any idea why?
@yoyo i think it's because the former uses "deltaY" as the offset for how much to scroll which can be smaller relative to the offset used in the latter which is 30/-30. instead i think you can set it to a much higher value like say 100 but you just have to test for the direction of the scroll. so if deltaY is negative, you want to use a negative offset for example -100 and vice versa if positive.
1

You can do this inline without the use of refs or hooks with the following code:

<div
  style={{ scrollbarColor="transparent", overflowX="auto" }}
  onWheel={(e) => {
    // here im handling the horizontal scroll inline, without the use of hooks
    const strength = Math.abs(e.deltaY);
    if (e.deltaY === 0) return;

    const el = e.currentTarget;
    if (
      !(el.scrollLeft === 0 && e.deltaY < 0) &&
      !(
        el.scrollWidth -
          el.clientWidth -
          Math.round(el.scrollLeft) ===
          0 && e.deltaY > 0
      )
    ) {
      e.preventDefault();
    }
    el.scrollTo({
      left: el.scrollLeft + e.deltaY,
      // large scrolls with smooth animation behavior will lag, so switch to auto
      behavior: strength > 70 ? "auto" : "smooth",
    });
  }}
>
// ...
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.