Home > Software engineering >  Grab the url fragment and expand the related accordion, scrolling to it
Grab the url fragment and expand the related accordion, scrolling to it

Time:03-10

I want to send mails with links to my faq-site, like http://www.test.com/faq#lorem_ipsum.

But my faq-site is made in react with multiple accordion components.

const faqQuestions = [
  {
    title: <h1 className="font-bold">question?</h1>,
    content: (
      <div className="px-4">
        test
      </div>
    ),
    accordionId: 'lorem_ipsum',
  },
]

const Faq = () => {
  // const [isExpanded, setIsExpanded] = useState(false);
  useLayoutEffect(() => {
    const anchor = window.location.hash.split('#')[1];
    if (anchor) {
      const anchorEl = document.getElementById(anchor);
      if (anchorEl) {
        anchorEl.scrollIntoView();
      }
    }
  }, []);

  return (
    <div className="container mx-auto px-10 lg:px-0">
      <div className="py-6">
        <p className="font-semibold text-3xl  text-primary">Häufige Fragen</p>
      </div>
      <div className="pb-10">
        {faqQuestions.map((question) => (
          <Accordion key={Math.random()} id={question.accordionId}>
            <AccordionSummary
              expandIcon={<FontAwesomeIcon icon={faChevronDown} />}
              aria-controls="panel1a-content"
            >
              <div>{question.title}</div>
            </AccordionSummary>
            <AccordionDetails>{question.content}</AccordionDetails>
          </Accordion>
        ))}
      </div>
    </div>
  );
};

I want that, when the user clicks on the link with anchor and jumps to the specific accordion AND the expand it. But i can't figure out, how to identify the accordion i'm jumping to. With plain javascript it's easy, but I can't find a solution with React.

Hope, that somebody could help me.

CodePudding user response:

As described in the mui documentation, you need to use a controlled accordion, using a state.

First, add a state to keep the name/id of the open accordion.

const [expanded, setExpanded] = useState(false);

Then, change you update function in order to grab the hash from the URL, check if a matching question exists inside your array, set the related accordion component as expanded, and finally scroll to it.

useLayoutEffect(() => {
  const anchor = window.location.hash.split('#')[1];
  if (anchor) {
    const accExists = faqQuestions.find(q => q.accordionId === anchor)
    if (accExists) {
      setExpandend(anchor);
      const anchorEl = document.getElementById(anchor);
      anchorEl.scrollIntoView();
    }
  }
}, []);

You also need to add an handler for clicks on the controlled accordion, to update the state with the name of the clicked accordion.

const handleChange = (panel) => (event, isExpanded) => {
  setExpanded(isExpanded ? panel : false);
};

Finally, change the JSX code in order to use this logic.

{faqQuestions.map((question) => (
  <Accordion
      key={question.accordionId}
      id={question.accordionId}
      expanded={expanded === question.accordionId}
      onChange={handleChange(question.accordionId)}>
    // ... your accordion content
  </Accordion>
))}
  • Related