I try to create a collapse and expand side menu in React (v 16.5)
with the following criteria -
On page load first item (Circulars) will be in expanded
To do that I would use React.useState
, since its a small state to control and to animate I would use CSS:
The component would look like this:
function SidebarNavs() {
const [activeItem, setActiveItem] = React.useState(1);
return (
<div className="sidebar-nav">
<div className="sidebar-nav-menu">
<SidebarItem
title="Circulars"
setActiveItem={setActiveItem}
index={1}
activeItem={activeItem}
>
Sidebar Content Here
</SidebarItem>
<SidebarItem
title="Specifications"
setActiveItem={setActiveItem}
index={2}
activeItem={activeItem}
>
Sidebar Content Here
</SidebarItem>
<SidebarItem
title="Specifications"
setActiveItem={setActiveItem}
index={3}
activeItem={activeItem}
>
Work Orders
</SidebarItem>
</div>
</div>
);
}
function SidebarItem({ title, children, setActiveItem, activeItem, index }) {
const expanded = activeItem === index;
const cls = "sidebar-nav-menu-item " + (expanded ? "item-active" : "");
return (
<div className={cls}>
<div className="sidebar-nav-menu-item-head">
<div className="sidebar-nav-menu-item-head-title">{title}</div>
<div className="sidebar-nav-menu-item-head-help">
<button
type="button"
className="btn-help"
onClick={() => setActiveItem(index)}
>
View more info
</button>
</div>
<div className="sidebar-nav-menu-item-head-icon">
<i className="fa fa-caret-down" aria-hidden="true" />
</div>
</div>
<div className="sidebar-nav-menu-item-body">{children}</div>
</div>
);
}
The CSS would look like this:
.sidebar-nav-menu-item {
border: 1px solid #CCC;
margin-bottom: 20px;
}
.sidebar-nav-menu-item .sidebar-nav-menu-item-body {
overflow: hidden;
max-height: 0;
transition: all linear 0.5s;
}
.sidebar-nav-menu-item.item-active .sidebar-nav-menu-item-body {
max-height: 100px;
transition: all linear 0.5s 0.3s;
}
You should use a state variable to show your collapsiable item active / in-active.
I modified your code a bit to fit it into your requirements.
class App extends Component {
constructor() {
super();
this.state = {
activeCollapse: 'circulars'
};
}
handleExpandCollaps = (name) => {
if (this.state.activeCollapse === name) {
this.setState({ activeCollapse: '' })
} else {
this.setState({ activeCollapse: name })
}
}
moreInfoClick = (e) => {
e.stopPropagation();
console.log("clicked");
}
render() {
return (
<div>
<div className="sidebar-nav">
<div className="sidebar-nav-menu">
<div className={`sidebar-nav-menu-item ${this.state.activeCollapse === "circulars" ? 'item-active' : ''}`} onClick={() => this.handleExpandCollaps("circulars")} data-id="circulars" >
<div className="sidebar-nav-menu-item-head">
<span className="sidebar-nav-menu-item-head-title">Circulars</span>
<span className="sidebar-nav-menu-item-head-help">
<button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
</span>
</div>
<div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
</div>
<div className={`sidebar-nav-menu-item ${this.state.activeCollapse === "specifications" ? 'item-active' : ''}`} onClick={() => this.handleExpandCollaps("specifications")} data-id="specifications">
<div className="sidebar-nav-menu-item-head">
<span className="sidebar-nav-menu-item-head-title">Specifications</span>
<span className="sidebar-nav-menu-item-head-help">
<button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
</span>
</div>
<div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
</div>
<div className={`sidebar-nav-menu-item ${this.state.activeCollapse === "wo" ? 'item-active' : ''}`} onClick={() => this.handleExpandCollaps("wo")} data-id="wo">
<div className="sidebar-nav-menu-item-head">
<span className="sidebar-nav-menu-item-head-title">Work Orders</span>
<span className="sidebar-nav-menu-item-head-help">
<button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
</span>
</div>
<div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
</div>
</div>
</div>
</div>
);
}
}
Note: I have used CSS
for font-awesome
icons. Hope you have added font-awesome
Demo