Creating a React Accordion Component Using Just CSS
2 min read
About a year ago now, I wrote a blog post on how to create an accordion component in React with Typescript and TailwindCSS. I recently needed to implement an accordion component again (this is why keeping a blog is so handy!), but this time in a codebase that doesn’t use TailwindCSS. Here’s a short follow-on to that post for how you’d create an accordion component if you were just using straight CSS. I'd recommend reading that post first if you're new to React, as it includes more detail on the order in which I built up the code.
Note that I’ve left most of the styling of the overall component out and focused on the important ones that effect the transition.
import React, { MutableRefObject, useRef, useState } from 'react'
import { appConfig } from '../appConfig'
interface AccordionProps {
title: React.ReactNode
content: React.ReactNode
}
export const Accordion: React.FC<AccordionProps> = ({ title, content }) => {
const [showExtraContent, setShowExtraContent] = useState(false)
const [height, setHeight] = useState('0px')
const contentSpace = useRef(null) as MutableRefObject<HTMLDivElement>
function toggleAccordion() {
setShowExtraContent((previousState) => !previousState)
setHeight(showExtraContent ? '0px' : `${contentSpace.current.scrollHeight}px`)
}
return (
<div className="container">
<button
onClick={toggleAccordion}
>
<p>{title}</p>
<img
src={'/assets/img/icons/chevron-up.svg'}
alt="Chevron icon"
className={`${showExtraContent ? 'rotate' : null} arrow`}
/>
</button>
<div
ref={contentSpace}
style={{ maxHeight: `${height}` }}
className="extra-content"
>
<div>{content}</div>
</div>
</div>
)
}
Here are the corresponding CSS styles.
.container {
display: flex;
flex-direction: column;
}
.arrow {
transition: 0.3s;
}
.rotate {
transform: rotate(180deg);
}
.extra-content {
overflow: hidden;
transition: max-height 0.3s ease-in-out;
}