UseAccordion
This useAccordion
Hook is used for
toggling the element such as Accordion
Type Declaration
accordion.ts
import { MutableRefObject } from 'react'
type Accordion = {
ref: MutableRefObject<any>
expanded: boolean
toggle: () => void
setCollapseState?: () => void
}
Use Accordion
useAccordion.tsx
import { useEffect, useRef, useState } from 'react'
export function useAccordion(deps = [], defaultExpanded = false): Accordion {
const ref = useRef<HTMLElement>()
const [expanded, setExpanded] = useState<boolean>(defaultExpanded)
const [sectionHeight, setSectionHeight] = useState(0)
// --- Collapse Function
function collapseSection(element: HTMLElement) {
let elementTransition = element.style.transition
element.style.transition = ''
requestAnimationFrame(function () {
element.style.height = sectionHeight + 'px'
element.style.transition = elementTransition
requestAnimationFrame(function () {
element.style.height = null
})
})
}
// --- SetCollapseState
function setCollapseState() {
setExpanded(false)
}
// --- Expand Section
function expandSection(element: HTMLElement) {
requestAnimationFrame(() => {
element.style.height = element.scrollHeight + 'px'
})
}
// -- Toggle
function toggle() {
if (expanded) {
collapseSection(ref.current)
setExpanded(false)
} else {
expandSection(ref.current)
setExpanded(true)
}
}
// --- Ref Style Height = Ref Scroll Height
useEffect(() => {
ref.current && setSectionHeight(ref.current.scrollHeight ?? 0)
if (ref.current && expanded) {
ref.current.style.height = ref.current.scrollHeight + 'px'
}
}, deps)
// --- Ref Current Expanded True False
useEffect(() => {
if (ref?.current) {
if (defaultExpanded) {
expandSection(ref?.current)
setExpanded(true)
} else {
setExpanded(false)
}
}
}, [defaultExpanded])
return {
ref,
expanded,
toggle,
setCollapseState,
}
}
Usage
FAQ.tsx
const FAQ = ({ question, answer }) => {
const { ref, expanded, toggle }: Accordion = useAccordion()
return (
<>
{/* Question */}
<div role={'button'} tabIndex={0} onClick={toggle}>
<h1>{question}</h1>
<DropDown expanded={expanded} />
</div>
{/* Answer */}
<div ref={ref}>
<div>{answer}</div>
</div>
</>
)
}