Make An Accordion Menu in React
Tags: react, javascript, css
Published: 2020-06-18 01:59:50

The accordion menu is used on websites to show important links with expanded information .It can be useful in many situations to add information to items in a list. So I am going to show you how to make an accordion menu with React. 

here is an example of the finished product: ![]( https://cdn.discordapp.com/attachments/699812263670055052/722989876353564743/ezgif.com-crop.gif)

This project will use two custom react components that I will walk through the process of making and explain how they work. These two components will be called `AccordionMenu` and `AccordionItem`. They will mostly be styled components but they will also wrap a lot functionality and reusability around native JSX elements.

this is the code for the `AccordionMenu` component

```js
import React, {useState, useEffect, useCallback} from 'react';

import "./Accordion.css";

const AccordionMenu = props => {
    const [children, setChildren] = useState([])
    const [openItem, setOpenItem] = useState()

    useEffect(() => {
        setChildren(() => props.children.length ? props.children : [props.children])
    }, [props.children])

    const clickHandler = useCallback(id => {
        setOpenItem(prev => {
            if(id === prev){
                return ""
            }else{
                return id
            }
        })
    }, [])

    return (
        <div className="accordion-menu">
            {children.map(elt => (
                <elt.type {...elt.props} open={elt.props.id === openItem} onClick={() => clickHandler(elt.props.id)}></elt.type>
            ))}
        </div>
    );
}

export default AccordionMenu;

```

The `AccordionMenu` component will have one or more children which are all should be `AccordionItem`'s. The children of the `AccordionMenu` will receive some extra props from their parent. The two extra props are `open` which is pretty self explanatory, its a boolean telling if the item is open or not, and `onClick` which is a function that will be called whenever an item is pressed and toggle its open status. The `openItem` state in the `AccordionMenu` will keep track of which item is open and if none are open it will be null. Having an `openItem` in the parent and using that to tell each item whether its open or not is what will allow us to have only zero to one items open at a time

This is the code for the `AccordionItem`.

```js
import React from "react";

const AccordionItem = props => {
	return (
		<div className="accordion-item">
			<div className="accordion-item--header" onClick={props.onClick}>
				{props.title}
			</div>
			<div className={`accordion-item--body ${props.open ? "open" : ""}`}>
                {props.children}
            </div>
		</div>
	);
};

export default AccordionItem;
```

The `AccordionItem` has a header and body. It takes in a `title` as prop and that title will be displayed in the header. All the children on the `AccordionItem` children will be rendered in the body. The header is what takes the `onClick` event from the `AccordionMenu`.

Now that we have the js code done all we need is the css to control the expanding of the items. I'll also add in some basic styles but I have intentionally made the styles simple so you can easily add your own styles and give it your own flare.

this code will go in `Accordion.css`
```css
.accordion-menu {
	padding: 1rem;
	width: fit-content;
}

.accordion-item {
	height: fit-content;
	width: 600px;
	max-width: 600px;
	margin: 0.5rem;
	border-radius: 0.5rem;
	overflow: hidden;
}

.accordion-item--header {
	height: 50px;
	padding: 0.5rem;
	background: chartreuse;
}

.accordion-item--body {
	height: 0px;
	transition: height 0.25s;
	overflow: hidden;
	background: orangered;
}

.accordion-item--body.open {
	height: 100px;
}

```

And with that you now have reusable components to add an accordion menu to your website