0

I have a react component which has quite a lot of components. Then I have this list which only has the overflow property as auto. The parent element for this list has a property overflow: hidden;

Now I am trying to scroll to an active element in the list based on certain criteria. I referred to this article [https://stackoverflow.com/questions/43441856/how-to-scroll-to-an-element][1] but then I got to understand that this will only work if the parent has a scroll property is there any other solution or a package to handle this.

//App.js

import React, { useRef, useEffect } from "react";
import "./App.css";
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const useMountEffect = (fun) => useEffect(fun, []);

const useScroll = () => {
  const htmlElRef = useRef(null);
  const executeScroll = () => {
    if (htmlElRef.current) window.scrollTo(0, htmlElRef.current.offsetTop);
  };

  return [executeScroll, htmlElRef];
};

const App = () => {
  const [executeScroll, elementToScrollRef] = useScroll();
  useMountEffect(executeScroll);
  return (
    <ul>
      {list.map((item) => (
        <li className="box" ref={item === 10 ? elementToScrollRef : null}>
          {item}
        </li>
      ))}
    </ul>
  );
};

export default App;

App.css

#root{
overflow:hidden;
}
ul {
  max-height: calc(100px + 2rem);
  overflow: auto;
}
.box {
  width: 100px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #eee;
  margin: 1rem;
}
classydraught
  • 352
  • 1
  • 4
  • 13

2 Answers2

0

You can use Element.scrollIntoView, which scrolls the parent container of an element to put it in view. Not supported by IE, and only partial support in Safari.

Steve -Cutter- Blades
  • 5,057
  • 2
  • 26
  • 40
0

I suggest you try the following method

// hook file

import { useState } from 'react';
// Restrict value to be between the range [0, value]
const clamp = (value) => Math.max(0, value);

// Check if number is between two values
const isBetween = (value, floor, ceil) => value >= floor && value <= ceil;

export const scrollSpy = () => {
  const [activeId, setActiveId] = useState('');

  function doScroll(e, ids, offset) {
    
    if (!activeId) {
      setActiveId(ids[0]);
    }
    const scroll = e.target.scrollTop;
    const position = ids
      .map((id) => {
        const element = document.getElementById(id);

        if (!element) return { id, top: -1, bottom: -1 };

        const rect = element.getBoundingClientRect();
        const top = clamp(rect.top + scroll - offset);
        const bottom = clamp(rect.bottom + scroll - offset);

        return { id, top, bottom };
      })
      .find(({ top, bottom }) => isBetween(scroll, top, bottom));

    if (position?.id) setActiveId(position?.id || '');
  }

  return [doScroll, activeId];
};

//inner comp

  const [doScroll, activeId] = scrollSpy();
return (
     onScroll={(e) => {
                doScroll(e, ids, 120);
              }}
)
Alireza Bagheri
  • 207
  • 3
  • 15