DEV Community

Bionic Julia
Bionic Julia

Posted on • Originally published at bionicjulia.com on

Creating a React Accordion Component Using Just CSS

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Like this post? Read more from me at https://bionicjulia.com/blog.

Top comments (0)