Search code examples
javascriptcssreactjsscrollviewjs-scrollintoview

scrollIntoView whole page shifting down


I want to build an indexed letters. When I click the letter (for example A,B,C). It should be scrolling to the belongs title. I used scrollIntoView here. Everythings okey except "block:start". When I want to the scrolling to title of start, whole page scrolling with container.

Here my gif about issue

enter image description here

Here my html & css & javascript code.

const scrollTo = id => {
let ref = document.getElementById(id)
if (ref /* + other conditions */) {
  ref.scrollIntoView({
    behavior: "smooth",
    block: "start",
    inline: "start",
  })
}

}

<div className="glossary">
    <div className="glossary-items grid">
      <div className="d-flex ">
        <div className="glossary-letters ">
          <ul>
            {letter.map(item => (
              <li onClick={() => scrollTo(item)}>
                <a> {item}</a>
              </li>
            ))}
          </ul>
        </div>
        <div className="glossary-titles">
          <ul>
            {glossary.map((item, index) => (
              <div key={item.group}>
                <li id={item.group}>{item.group}</li>
                {item.children.map((item2, i) => (
                  <li key={i}>
                    <Link
                      activeClassName="glossary-titles-active"
                      to={`/en/sozluk/${item2.first_name + item2.id}`}
                    >
                      {item2.first_name}
                    </Link>
                  </li>
                ))}
              </div>
            ))}
          </ul>
        </div>
      </div>
      <div className="glossary-content ml-5">
        <Router>
          <Glossary path="en/sozluk/:id" />
        </Router>
      </div>
    </div>
  </div>

Solution

  • There is related question to that

    You could use scrollTo function of the parent element to scroll to specific child element.

    Example

    const { useState, useEffect, useRef } = React;
    const App = () => {
      const [list, setList] = useState([]);
      const [keywords, setKeywords] = useState([]);
      const refs = useRef(null);
      const parentRef = useRef(null);
      
      useEffect(() => {
        const newList = Array(25).fill(0).map((pr, index) => String.fromCharCode(65 + index));
        const newKeywords = newList.flatMap(pr => [pr, ...newList.map(npr => pr + npr)]);
        
        refs.current = newList.reduce((acc, letter) => {
          acc[letter] = React.createRef();
          return acc;
        }, {});
        
        setList(newList);
        setKeywords(newKeywords);
      }, [])
      
      const onClick = ({target: {dataset: {letter}}}) => {
        const element = refs.current[letter].current;
        const parent = parentRef.current;
        
        const onScroll = () => {
          const relativeTop = window.scrollY > parent.offsetTop ? window.scrollY : parent.offsetTop
        
          parent.scrollTo({
            behavior: "smooth",
            top: element.offsetTop - relativeTop
          });
        }
        
        window.removeEventListener("scroll", onScroll);
        window.addEventListener("scroll", onScroll);
        
        onScroll();
        
        /*
        element.scrollIntoView({
          behavior: "smooth",
          block: "start",
          inline: "start",
        })
        */
      }
      
      const tryAssignRef = (letter) => {
        return list.indexOf(letter) > -1 ? {ref: refs.current[letter]} : {};
      }
    
    /// ...{ref: {refs.current['A']}}
      return <div className="container">
        <div className="header">
        </div>
        <div className="body">
          <div className="left">
            <div className="letters">{list.map(pr => <div className="letter" onClick={onClick} data-letter={pr} key={pr}>{pr}</div>)}</div>
            <div ref={parentRef} className="keywords">{keywords.map(pr => <div {...tryAssignRef(pr)} key={pr}>{pr}</div>)}</div>
          </div>
          <div className="right">
          </div>
        </div>
      </div>
    }
    
    ReactDOM.render(
        <App />,
        document.getElementById('root')
      );
    .container, .body, .left {
      display: flex;
    }
    
    .container {
      flex-direction: column;
    }
    
    .header {
      flex: 0 0 100px;
      border: 1px solid black;
    }
    
    .body {
      height: 1000px;
    }
    
    .left {
      flex: 1;
    }
    
    .right {
      flex: 2;
    }
    
    .left { 
      justify-content: space-between;
    }
    
    .letter {
      padding: 2px 0;
      cursor: pointer;
    }
    
    .letters, .keywords {
      padding: 0 10px;
    }
    
    .keywords {
      overflow-y: scroll;
    }
    <script src="https://unpkg.com/react/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    <div id="root"></div>