From 07de9b138cd9ca93148d690a921ec7996ef549dd Mon Sep 17 00:00:00 2001 From: bendtherules Date: Fri, 23 Oct 2020 18:45:51 +0530 Subject: [PATCH] Accordion - Handle auto-open if inner element is linked to --- components/Accordion.jsx | 61 +++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/components/Accordion.jsx b/components/Accordion.jsx index b8a8916..860c449 100644 --- a/components/Accordion.jsx +++ b/components/Accordion.jsx @@ -1,10 +1,57 @@ -import React from "react"; +import React, { useRef, useEffect } from "react"; -const Accordion = ({ children, title = "More" }) => ( -
- {title} - {children} -
-); +const Accordion = ({ children, title = "More" }) => { + const detailsRef = useRef(null); + const summaryRef = useRef(null); + + function openAccordionOnHash() { + const hash = location.hash.substring(1); + if (hash.length === 0) { + return; + } + let targetElement; + targetElement = document.getElementById(hash); + if (targetElement === null) { + return; + } + + // 1. If target is within current details element + const detailsElement = detailsRef.current; + const summaryElement = summaryRef.current; + if ( + detailsElement !== null && + summaryElement.current !== null && + detailsElement.contains(targetElement) + ) { + // 2. and it is not open, + if (!detailsElement.open) { + // 3. Then open it + detailsElement.open = true; + // 4. and scroll into view, focus on summary + summaryElement.focus(); + targetElement.scrollIntoView({ behavior: "smooth", block: "center" }); + } + } + } + + useEffect(() => { + // 1. Add event listener for future hash changes + window.addEventListener("hashchange", openAccordionOnHash); + // 2. Do it anyway now if initial url has hash + openAccordionOnHash() + + // Cleanup - remove listener + return () => { + window.removeEventListener("hashchange", openAccordionOnHash); + }; + }, []); + + return ( +
+ {title} + {children} +
+ ); +}; export default Accordion;