I have created a react component for sidebar menu. I do not want to use bootstrap accordian for the purpose. I want to create a menu list with plus minus sign toggle. In the code below, if list items under Technical analysis are open it should show "Technical Analysis -". How can I achieve similar list as pic attached?
import React, {Fragment, useState} from "react";
import {Col, Collapse, Container, ListGroup, ListGroupItem, Row} from "react-bootstrap";
import {Link, useRouteMatch} from "react-router-dom";
import ListItem from "@material-ui/core/ListItem";
import List from "@material-ui/core/List";
const SidebarL = () => {
const [open, setOpen] = useState(false);
const [open1, setOpen1] = useState(false);
const [open2, setOpen2] = useState(false);
let {url} = useRouteMatch();
return (
<Container>
<Row>
<Col>
<div onClick={() => setOpen(!open)}
aria-controls="collapse-text"
aria-expanded={open}
>
<Link style={{textDecoration: "none", color: "black"}}>
<div>
Technical Analysis
</div>
</Link>
</div>
<Collapse in={open}>
<div id="collapse-text">
<ul className="list-unstyled border-left p-2 ml-2">
<li>
<Link to={`${url}/thedowtheory`}
style={{textDecoration: "none"}}
>
The Dow Theory
</Link>
</li>
<li>
<Link to={`${url}/charts`}
style={{textDecoration: "none"}}>
Chart & Chart Patterns
</Link>
</li>
<li>
<Link to={`${url}/trendlines`}
style={{textDecoration: "none"}}>
Trend & Trend Lines
</Link>
</li>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}>
Support & Resistance
</Link>
</li>
</ul>
</div>
</Collapse>
<hr className="mt-2 mb-2" />
<div onClick={() => setOpen1(!open1)}
aria-controls="collapse-text1"
aria-expanded={open1}
>
<Link style={{textDecoration: "none", color: "black"}}>
<div>Fundamental Analysis </div>
</Link>
</div>
<Collapse in={open1}>
<div id="collapse-text1" >
<ul className="list-unstyled border-left p-2 ml-2"
>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
</ul>
</div>
</Collapse>
<hr className="mt-2 mb-2" />
<div onClick={() => setOpen2(!open2)}
aria-controls="collapse-text2"
aria-expanded={open2}
>
<Link style={{textDecoration: "none", color: "black"}}>
Elliot Wave Analysis
</Link>
</div>
<Collapse in={open2}>
<div id="collapse-text2" >
<ul className="list-unstyled border-left p-2 ml-2"
>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
<li>
<Link to={`${url}/supportresistance`}
style={{textDecoration: "none"}}
>
Link
</Link>
</li>
</ul>
</div>
</Collapse>
</Col>
<Col xs={7} className="border-left">
Content
</Col>
<Col className="border-left">
SidebarR
</Col>
</Row>
</Container>
)
}
export default SidebarL
This answer assumes you're asking about the mechanics of such a menu and not the specifics of the styling.
For the accordion, create a configuration object that represents the menu items. There are many ways you could do this, but here's an example tree structure that would accommodate a submenus of any depth:
const menu = [
{
title: 'Getting Started with Technical Analysis',
items: [
{
title: 'Best ways to learn technical analysis',
href: `${url}/best-ways-to-learn`,
},
{
title: 'Top 7 Books',
href: `${url}/top-7-books`,
},
],
},
{
title: 'Essential Technical Analysis Strategies',
items: [
{
title: 'Intro to Strategies',
href: `${url}/intro-to-strategies`,
}
],
}
];
With this structure in place you can create a recursive menu item component that renders an entry's title and its children:
const MenuItem = ({ item: { title, items = [], href } }) => (
<li>
<div className='menu-item-title'>{title}</div>
{ items.length && (
<ul className='submenu'>
{ items.map( item => <MenuItem key={item.title} item={item} /> ) }
</ul>
)}
</li>
)
With that in place you can add a bit of component state and css to expand/collapse the submenus:
// adding expanded/collapsed state to MenuItem component from before
const MenuItem = ({ item: { title, items = [], href } }) => {
const [expanded, setExpanded] = React.useState(false);
const clickHandler = React.useCallback(() => setExpanded(!expanded), [expanded]);
return (
<li onClick={clickHandler} className={expanded ? 'expanded' : 'collapsed'}>
<div className='menu-item-title'>{title}</div>
{ items.length && (
<ul className='submenu'>
{ items.map( item => <MenuItem key={item.title} item={item} /> }
</ul>
)}
</div>
</li>
);
}
You can control the rest with CSS.
.collapsed .submenu {
height: 0;
overflow: hidden;
}
If you only want one item expanded at a time you could pass an onChange handler from the top that could collapse other items when something is expanded.