The source code for this library is available on GitHub.

Vaiva's Pattern Library.

Accordion

Accordion that maps through an array (accordionList) of objects (ENTRIES: title, content) and returns an expandable accordion item.


import React, { useState } from 'react';
import rightArrow from '../../images/right-arrow.svg';
import styled from 'styled-components';

const StyledAccordion = styled.dl`
  display: flex;
  flex-direction: column;
  gap: 1.5rem;

  dt {
    display: flex;
    justify-content: space-between;
    cursor: pointer;
  }

  dt[aria-expanded='true'] img {
    transform: rotateZ(90deg);
  }

  .list-group {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    border-top: 1px solid black;
    padding: 1.5rem 0 3.5rem 0;
  }

  img {
    transition: all 0.35s ease;
  }

  dd {
    overflow: hidden;
    max-height: 50rem;
    transition: max-height 1.5s ease-in-out;
  }

  dd[aria-expanded='true'] {
    max-height: 0px;
    transition: max-height 1s cubic-bezier(0, 1, 0, 1);
  }
`;

const Accordion = ({ accordionList }) => {
  const [open, setOpen] = useState(accordionList.map(accordion => false));
  const [focused, setFocused] = useState(accordionList.map(accordion => false));

  const toggleAccordion = idx => {
    setOpen({ ...open, [idx]: !open[idx] });
  };

  const handleKeyboardListener = (e, idx) => {
    if (e.key === ' ' && focused[idx]) {
      e.preventDefault();
      let newOpen = open;
      newOpen[idx] = !open[idx];
      setOpen(newOpen);
    }
  };

  const handleFocus = (e, idx) => {
    let newFocused = focused;
    newFocused[idx] = !focused[idx];
    setFocused(newFocused);
  };

  return (
    <StyledAccordion>
      {accordionList.map((acc, idx) => (
        <React.Fragment key={idx}>
          <div className="list-group">
            <dt
              onClick={() => toggleAccordion(idx)}
              onKeyDown={e => handleKeyboardListener(e, idx)}
              onFocus={e => handleFocus(e, idx)}
              onBlur={e => handleFocus(e, idx)}
              aria-expanded={open[idx]}
              tabIndex={'0'}
              role="button"
            >
              {acc.title}
              <img src={rightArrow} alt="collapse accordion" />
            </dt>
            <dd aria-expanded={!open[idx]}>{acc.content}</dd>
          </div>
        </React.Fragment>
      ))}
    </StyledAccordion>
  );
};
export default Accordion;    

More Components

TailwindCSS Text Carousel

The title speaks volumes.

Button

There is no description. Have a poem instead.

When I heard the learn’d astronomer,
When the proofs, the figures, were ranged in columns before me,
When I was shown the charts and diagrams, to add, divide, and measure them,
When I sitting heard the astronomer where he lectured with much applause in the lecture-room,
How soon unaccountable I became tired and sick,
Till rising and gliding out I wander’d off by myself,
In the mystical moist night-air, and from time to time,
Look’d up in perfect silence at the stars.