react-accordion-with-header

React accordion component with customizable flexbox header

I was inspired to build this by my own actual need for a flexible accordion component. I was looking to make a clone of the fantastic https://darksky.net/ as a react side project. Notice their accordion component with a super custom header panel:

ds

This is what I wanted but could not find out there in the open source world: a flexible component that allows full customization of the HEADER of the expandable panel.

Having some spare time on my hands, I made it.

This project was both a study in making a flexible and installable React component as well as learning npm. In doing so, I've come to the conclusion that npm is an amazing tool that is unfairly hated on all to much. Javascript developers: can you imagine if it didn't exist? How much different would your workflow be?

The component

To achieve the flexible horizontal (and vertical) layout, it uses flexbox as a basis for alignment of the <AccordionHeader /> component. A template can be passed in as a component via props or as children, as well as plain html.

Check out the demo NOW

Install via NPM:

npm install react-accordion-with-header  

Import the modules:

import {  
    AccordionWithHeader,
    AccordionNode,
    AccordionHeader,
    AccordionPanel
} from 'react-accordion-with-header';

Items can be passed in to <AccordionHeader /> and <AccordionPanel /> one of three ways:

  • a component passed into the template prop
  • a component passed into the body (in between opening and closing tags of parent components)
  • as plain html

NOTE: We cannot pass in a stateless component as a template at this time because of the way we use refs to calculate height... and according to react: "Stateless function components cannot be given refs"

The elements passed in to <AccordionHeader /> can be horizontally justified and vertically aligned via their respective props
:tada: :boom: :beers:

  • horizontalAlignment
  • verticalAlignment

Pass in a component as a template via template prop:

class HeaderTpl extends React.Component {  
   render() {
     return (
       <header>
         <img src={`http://www.stevensegallery.com/100/10${(Math.floor(Math.random() * 5) + 1)}`}/>
         <img src={`http://www.stevensegallery.com/100/10${(Math.floor(Math.random() * 5) + 1)}`}/>
       </header>
     );
   }
 }

 class BodyTpl extends React.Component {
   render() {
     return (
       <article>
         <figcaption>...the blood bank</figcaption>
         <img src={`http://www.stevensegallery.com/200/20${(Math.floor(Math.random() * 5) + 1)}`}/>
       </article>
     );
   }
 }

...

  render() {
    return (
      <AccordionWithHeader>
        {[1, 2, 3, 4].map((item, i) => {
          return (
            <AccordionNode key={i}>
              <AccordionHeader template={<HeaderTpl />} horizontalAlignment="centerSpaceBetween" />
              <AccordionPanel template={<BodyTpl />} />
            </AccordionNode>
          );
        })}
      </AccordionWithHeader>
    );
  }

Pass in a component as children:

…
  render() {
    return (
      <AccordionWithHeader>
        {[1, 2, 3, 4].map((item, i) => {
          return (
            <AccordionNode key={i} className="foobar-node">
              <AccordionHeader className="foobar-header"
                               titleColor="#607D8B"
                               horizontalAlignment="centerSpaceAround"
                               verticalAlignment="center">
                <HeaderTpl />
              </AccordionHeader>
              <AccordionPanel>
                <BodyTpl />
              </AccordionPanel>
            </AccordionNode>
          );
        })}
      </AccordionWithHeader>
    );
  }
…

...or as plain HTML

…
  render() {
    return (
      <AccordionWithHeader>
        {[1, 2, 3, 4].map((item, i) => {
          return (
            <AccordionNode key={i}>
              <AccordionHeader>
                <div>
                  <h2>Some title!</h2>
                </div>
              </AccordionHeader>
              <AccordionPanel>
                <section>
                  <header>Some body information etc</header>
                  <article>Interesting things...</article>
                </section>
              </AccordionPanel>
            </AccordionNode>
          );
        })}
      </AccordionWithHeader>
    );
  }
…

options / PropTypes

AccordionWithHeader

Property Type Description Default
firstOpen Boolean Determines if the first panel should be expanded by default false
multipleOkay Boolean True allows multiple panels to be expanded at the same time. False allows only one panel to be expanded at any time. false
className String Custom classname applied to root item div null

AccordionNode

Property Type Description Default
className String Custom classname applied to root item div null

AccordionHeader

Property Type Description Default
title String For simple headers, a title will render an <h1> and disallow child elements null
titleColor String some valid CSS color or rgb or hex black
horizontalAlignment String One of: 'centerSpaceBetween', 'centerSpaceAround', 'center', 'left', 'right'. Maps to corresponding flex-box CSS property centerSpaceAround
verticalAlignment String One of: 'top', 'center', 'bottom' center
className String Custom classname applied to root div accordion-header
style Object Inline styles applied to root div null
template Element Component to be rendered as a template null

AccordionPanel

Property Type Description Default
template Element Component to be rendered as a template null
speed Number Speed in milliseconds to apply to CSS transition of open/close effect 250

Roadmap

  • add callbacks to open/close methods
  • add tests