Reputation: 117
I have a scrollable list of elements on the page, divided into sections. Each section is associated with a tab of the section name above the list. When I click on a particular Tab, the list scrolls automatically to the section of the tabs name.
<Tab value="one" active={current === 'one'} onClick={() => handlerScroll(sect1, 'one')}>
Section1
</Tab>
This is how Tab's press is processed and the scroll occurs - I change the state to the selected value, and I scroll through the list using scrollIntoView to the beginning of the selected section, referring to the section through ref:
сonst [current, setCurrent] = React.useState('one');
const handlerScroll = (tab, current) => {
setCurrent(current);
tab.current.scrollIntoView({ block: "start", behavior: "smooth" });
};
The first argument is ref to the clicked section of the list:
const sect1 = useRef();
<div ref={sect1}>
</div>
The scroll works. BUT, when i clicked, the browser window "scrolls" to the top of the list (the page literally descends to the top border of the div, where the entire list is located), and only then the list itself scroll to the clicked section.
Is it possible to somehow disable the scrolling of the browser window, so that the page itself does not move anywhere, but only the contents of the list change and scroll when you press Tab?
Upvotes: -1
Views: 738
Reputation: 17554
scrollIntoView
will scroll the whole page to the target element
.
I suggest you scroll the child element relative to its' parent element.
function scrollParentToChild(parent, child) {
// Where is the parent on page
var parentRect = parent.getBoundingClientRect();
// What can you see?
var parentViewableArea = {
height: parent.clientHeight,
width: parent.clientWidth
};
// Where is the child
var childRect = child.getBoundingClientRect();
// Is the child viewable?
var isViewable = (childRect.top >= parentRect.top) && (childRect.bottom <= parentRect.top + parentViewableArea.height);
// if you can't see the child try to scroll parent
if (!isViewable) {
// Should we scroll using top or bottom? Find the smaller ABS adjustment
const scrollTop = childRect.top - parentRect.top;
const scrollBot = childRect.bottom - parentRect.bottom;
if (Math.abs(scrollTop) < Math.abs(scrollBot)) {
// we're near the top of the list
parent.scrollTop += scrollTop;
} else {
// we're near the bottom of the list
parent.scrollTop += scrollBot;
}
}
}
And you can achieve the smooth behavior with
.parent {
scroll-behavior: smooth;
}
Another solution you can use scrollintoviewifneeded
instead of scrollIntoView
but it's not supported on Firefox and IE at all.
Upvotes: 0