How to horizontally scroll a table with mouse wheel in react?
Use onWheel event
The
onwheel
event occurs when the mouse wheel is rolled up or down over an element.
With Element.scrollTo(), Element.scrollLeft
The
scrollTo()
method of the Element interface scrolls to a particular set of coordinates inside a given element.
element.scrollTo({
top: 100,
left: 100,
behavior: 'smooth'
});
Code sample:
const onWheel = e => {
e.preventDefault();
const container = document.getElementById("container");
const containerScrollPosition = document.getElementById("container").scrollLeft;
container.scrollTo({
top: 0,
left: containerScrollPosition + e.deltaY,
behaviour: "smooth"
});
};
<div className="container" id="container" onWheel={onWheel}>
Refer: Horizontal Scrolling on React Component Using Vertical Mouse Wheel
horizontally scroll a table with mouse wheel in react without DOM Selector?
Using document.getElementById
is a react anti-pattern. Use a react ref
to access a DOM node.
refs and the dom
Since you have a functional component you can use the useRef
hook, otherwise, the createRef
can be used for a class-based component.
useRef
Moved the onWheel
handler into the component so the ref is in scope. Also removed the optional behavior option, it was misspelled and using the default behavior, which is what you want anyway.
function App() {
const onWheel = e => {
e.preventDefault();
const container = scrollRef.current;
const containerScrollPosition = scrollRef.current.scrollLeft;
container.scrollTo({
top: 0,
left: containerScrollPosition + e.deltaY,
});
};
const scrollRef = useRef(null);
const num = 50;
let points_th = [];
for (let i = 0; i < num; i++) {
points_th.push(<th>Points</th>);
}
let row_1 = render_row("Jill", "Smith", 50, num);
let row_2 = render_row("Eva", "Jackson", 94, num);
let row_3 = render_row("Adam", "Johnson", 67, num);
return (
<div>
<div
ref={scrollRef}
className="container"
id="container"
onWheel={onWheel}
>
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
{points_th}
</tr>
{row_1}
{row_2}
{row_3}
</table>
</div>
</div>
);
}
How to do React-horizontal scroll using mouse wheel
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.
Horizontal scroll with mouse wheel on horizontal list
You just forget to add JQuery to your html
http://jsfiddle.net/902tjbzz/
jquery.js
: http://code.jquery.com/jquery-2.1.4.min.js
react horizontal scroll to section with mouse wheel
I've modified your sandbox Working Demo.
Did following changes:
- Created
navRefs
for each menu item. And did the same thing withnavRefs
as you did withscrollRefs
.
// called it when user scrolls vertically, or clicks on a menu item
navRefs.current[i].current.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "center"
});
- Changed logic to find currently focused content.
const isVisible =
elemTop < window.innerHeight / 2 && elemBottom > window.innerHeight / 2;
In short if content is on viewport's horizontal center then select it. This avoids selecting multiple contents if many of them are in viewport at the same time.
- Used a flag to avoid executing
scrollHandler
when user clicks on a menu item. Also avoided the horizontal scroll events on navbar. - In CSS hide horizontal scrollbar on navbar. And added red underline to selected menu item.
import "./styles.css";
import React, { createRef, useRef, useState, useEffect } from "react";
var scrolling = false;
export default function App() {
const scrollRefs = useRef([]);
const navRefs = useRef([]);
const [active, setActive] = useState(0);
const list = [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
"Item 8",
"Item 9",
"Item 10"
];
scrollRefs.current = [...Array(list.length).keys()].map(
(_, i) => scrollRefs.current[i] ?? createRef()
);
navRefs.current = [...Array(list.length).keys()].map(
(_, i) => navRefs.current[i] ?? createRef()
);
const scrollTo = (index) => {
console.log("setting scrolling" + scrolling);
scrolling = true;
scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
setActive(index);
setTimeout(() => {
scrolling = false;
navRefs.current[index].current.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "center"
});
}, 1000);
};
const scrollHandler = (e) => {
// handle scroll only on body
// we don't want to handle horizontal scroll on nav bar
if (e.target !== document) return;
if (scrolling === true) return;
const scrollRefsElements = scrollRefs.current;
scrollRefsElements.forEach((el, i) => {
const rect = el.current.getBoundingClientRect();
const elemTop = rect.top;
const elemBottom = rect.bottom;
const isVisible =
elemTop < window.innerHeight / 2 && elemBottom > window.innerHeight / 2;
if (isVisible) {
navRefs.current[i].current.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "center"
});
setActive(i);
}
});
};
useEffect(() => {
window.addEventListener("scroll", scrollHandler, true);
return () => {
window.removeEventListener("scroll", scrollHandler, true);
};
}, []);
return (
<div className="container">
<ul className="myMenu nav list-unstyled d-flex flex-nowrap fixed-top">
{list.map((item, i) => (
<li className="nav-item " key={i} ref={navRefs.current[i]}>
<a
href={`#s-${i}`}
className={`nav-link text-nowrap ${
active === i ? "text-danger" : ""
}`}
onClick={(e) => {
scrollTo(i);
}}
>
{item}
</a>
</li>
))}
</ul>
<ul className="mb-100 list-unstyled">
{list.map((item, i) => (
<li id={`s-${i}`} ref={scrollRefs.current[i]} className="py-100 px-3">
<h3>{item}</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi,
dicta.
</p>
</li>
))}
</ul>
</div>
);
}
Horizontal Scrolling on React Component Using Vertical Mouse Wheel
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
Related Topics
How to Find the Width of a Div Using Vanilla JavaScript
Refresh a Div That Has a Google Ad Inside It
Adding Multiple Event Listeners to One Element
How to Format/Tidy/Beautify in JavaScript
What Is the Correct Way to Write HTML Using JavaScript
Loading an Image to a <Img> from <Input File>
How to Create a Custom Scrollbar on a Div (Facebook Style)
How to "Reset" <Div> to Its Original State After It Has Been Modified by JavaScript
JavaScript - Head, Body or Jquery
Getting Mouse Location in Canvas
How to Export HTML Table to Excel Using JavaScript
How to Curve/Arc Text Using CSS3/Canvas
How to Disable Href If Onclick Is Executed
Load HTML File Contents to Div [Without the Use of Iframes]
Force Browser to Trigger Reflow While Changing CSS
How to Use JavaScript to Change the Form Action
How to Use JavaScript to Dynamically Change a Video's Source