lcnw
lcnw

Reputation: 117

How to prevent the browser window from scrolling when scrolling to item in list on page?

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

Answers (1)

Mina
Mina

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.

Resource

Upvotes: 0

Related Questions