'React Bootstrap scroll down to content after accordion is opened

I have a react bootstrap table column accordion that has content in it. I am facing the issue is if panel opens user unable to identify the content until scroll down.

I wanted to be able to scroll down to the content when accordion collapse is opened.

This is what my parent function component looks like,

import React, {forwardRef, useContext} from "react";
import AccordionContext from "react-bootstrap/AccordionContext";
import {  Table } from "react-bootstrap";

function CustomToggle({ children, eventKey, callback, className }) {

    const currentEventKey = useContext(AccordionContext);
    const decoratedOnClick = useAccordionToggle(
        eventKey,
        () => {
            let eventType = `${currentEventKey ? 'close' : 'open'}`;
            callback && callback(eventKey,eventType)
            
        },
      );

    return (
        <tr onClick={decoratedOnClick}>
            <td><Image src={"accordion_arrow_down.svg"} /></td>
        </tr>
    )
}

function ParentComponent()
{
    const scrollDownRef = React.useRef(null);

    const toggleHandle = (eventKey,eventType) => {
        
        if(scrollDownRef && scrollDownRef.current) {
            scrollDownRef.current.scrollIntoView({
                behavior: "smooth",
                block: "nearest",
                inline: "start"
              });
        }
    }

    return (
        <div>
            <Table>
                <tbody>
                    <CustomToggle callback={toggleHandle} eventKey={{}} />
                    <tr>
                        <td>
                    <Accordion.Collapse eventKey={{}}>
                        <ChildComponent ref={scrollDownRef} />
                    </Accordion.Collapse>
                        </td>   
                    </tr>
                </tbody>
            </Table>
        </div>
    )
}

and child component looks like below,

function ChildComponent({ref}) {
    return (
        <div>
            <Form>
                <div ref={ref}>

                </div>
            </Form>
        </div>
    )
}

export default forwardRef(ChildComponent)

I have also tried with setTimeout function as well, if the ref element has to be identified if there is any delay with the accordion open time. Nothing worked here.

I have tried other scroll methods in the place of scrollIntoView funtion. But neither do anything to the page.

Any help would be appreciated!



Solution 1:[1]

I have tried to use your code but it contains many errors here and there. So I have created a simple example that you can use.

In App.js

import React, { useState, forwardRef, useRef } from "react";

import { Accordion, Table, Card, Container } from "react-bootstrap";

const ChildComponent = forwardRef((props, ref) => {
  return (
    <div>
      <Accordion.Collapse eventKey="0" className="border">
        <Card.Body
          style={{ height: "calc(100vh + 200px)" }}
          className="d-flex align-items-end justify-content-center"
        >
          <Container>
            <div ref={ref}> Some Content. Lorem Ipsum. Hello World.</div>
          </Container>
        </Card.Body>
      </Accordion.Collapse>
    </div>
  );
});

const App = () => {
  const [activeEventKey, setActiveEventKey] = useState("");
  const accordElem = useRef(null);

  const handleClickToggle = (eventKey) => {
    if (eventKey === activeEventKey) {
      setActiveEventKey("");
    } else {
      setActiveEventKey(eventKey);
      //Handle Scroll here when opening
      setTimeout(() => {
        accordElem.current.scrollIntoView({
          behavior: "smooth",
          block: "end",
          inline: "nearest",
        });
      }, 400);
    }
  };

  return (
    <div>
      <Accordion activeKey={activeEventKey}>
        <Table>
          <tbody>
            <tr>
              <Accordion.Toggle
                as="td"
                eventKey="0"
                onClick={() => handleClickToggle("0")}
              >
                Add Mock
              </Accordion.Toggle>
            </tr>
            <tr>
              <td>
                <ChildComponent ref={accordElem} />
              </td>
            </tr>
          </tbody>
        </Table>
      </Accordion>
    </div>
  );
};

export default App;

Explanation:

  • I used Card, Container components for the purpose of demonstration. I added some styles as well to make sure accordion content is taller than my screen size so scrolling can be seen
  • Instead of Custom Toggle, you can use Accordion.Toggle and give the value as='td' for it to be used as a element.
  • You can use setTimeout so that component is rendered and ref is not null

Here is a CodeSandbox link with example : https://codesandbox.io/s/festive-sun-o0e4ih

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Surya K