I have used onClick to change the classname in css. I have used same classname for all the features. So onClick a particular feature I want that features submenus to dropdown not all the features. How can I get this done so that I could only open a particular feature’s submenu. I have even attached the snip where I have clicked just the feature-2, but all the features are opened.-
https://i.stack.imgur.com/ayPcI.png
import {React,useState,useEffect,useCallback } from 'react';
import { Tabs } from 'antd';
import 'antd/dist/antd.css';
const { TabPane } = Tabs;
const Navbar = (props) => {
const [inactive, setInactive] = useState(true);
const [expand, setExpand] = useState(false);
const [focusingPaneKey, setFocusingPaneKey] = useState('')
const [openingPaneKeys, setOpeningPaneKeys] = useState([])
const openPane = (paneKey) => {
setOpeningPaneKeys(oldState => {
if (!oldState.includes(paneKey)) {
return [...oldState, paneKey]
}
return oldState
})
setFocusingPaneKey(paneKey)
}
const closePane = (paneKey) => {
if (paneKey === focusingPaneKey) {
const paneKeyIndex = openingPaneKeys.indexOf(paneKey)
setFocusingPaneKey(openingPaneKeys[paneKeyIndex - 1])
}
setOpeningPaneKeys(openingPaneKeys.filter((openingPaneKey) => openingPaneKey !== paneKey))
}
const handleTabsEdit = useCallback((key, action) => {
if (action === 'remove') {
closePane(key)
}
}, [closePane])
useEffect(() => {
if(inactive) {
document.querySelectorAll(".sub-menu").forEach((el) => {
el.classList.remove("active");
});
}
props.onCollapse(inactive);
}, [inactive]);
// const { panes } = props
const keysOfPane = Object.keys(panes)
return (
<><div className={`side-navbar ${inactive ? "inactive" : ""}`}>
<div className="top-section">
<div onClick={() => { setInactive(!inactive); } } className="menu-btn">
{inactive ? (
<i class="bx bx-menu"></i>
) : (
<i class='bx bx-x'></i>)}
</div>
</div>
<div className="search-box">
<button className="search-btn">
<i class='bx bx-search'></i>
</button>
<input type="text" placeholder="search" />
</div>
<div className="divider"></div>
<div className="main-menu">
<ul>
<li>
<a onClick={() => openPane('1')} className="menu-item">
<div className="menu-icon">
<i class='bx bx-grid-alt'></i>
</div>
<span>Feature-1</span>
</a>
</li>
<li onClick ={() => setExpand(!expand)}>
<a onClick={() => openPane('2')} className="menu-item">
<div className="menu-icon">
<i class='bx bx-grid-alt'></i>
</div>
<span>Feature-2</span>
<div className="drop-down">
<i class='bx bxs-down-arrow'></i>
</div>
</a>
<ul className={`sub-menu ${expand ? 'active' : ""}`}>
<li> <a>sub-menu-1</a> </li>
<li> <a>sub-menu-2</a> </li>
<li> <a>sub-menu-3</a> </li>
</ul>
</li>
{/* <MenuItem
name = {" Feature-2 "}
subMenus = {[
{name: "sub-menu-1"},{name: "sub-menu-2"},{name: "sub-menu-3"}
]}
/> */}
<li onClick ={() => setExpand(!expand)}>
<a className="menu-item">
<div className="menu-icon">
<i class='bx bx-grid-alt'></i>
</div>
<span>Feature-3</span>
<div className="drop-down">
<i class='bx bxs-down-arrow'></i>
</div>
</a>
<ul className={`sub-menu ${expand ? 'active' : ""}`}>
<li> <a>sub-menu-1</a> </li>
<li> <a>sub-menu-2</a> </li>
<li> <a>sub-menu-3</a> </li>
</ul>
</li>
<li onClick ={() => setExpand(!expand)}>
<a className="menu-item">
<div className="menu-icon">
<i class='bx bx-grid-alt'></i>
</div>
<span>Feature-4</span>
<div className="drop-down">
<i class='bx bxs-down-arrow'></i>
</div>
</a>
<ul className={`sub-menu ${expand ? 'active' : ""}`}>
<li> <a>sub-menu-1</a> </li>
<li> <a>sub-menu-2</a> </li>
<li> <a>sub-menu-3</a> </li>
</ul>
</li>
</ul>
</div>
</div>
<div>
<Tabs
hideAdd
onChange={openPane}
activeKey={focusingPaneKey}
type="editable-card"
onEdit={handleTabsEdit}
>
{openingPaneKeys
.map((key) => panes[key])
.map((pane) => (
<TabPane tab={pane.title} key={pane.key}>
{pane.content}
</TabPane>
))}
</Tabs>
</div>
</>
);
};
const panes = {
1: { key: '1', title: 'Feature 1', content: 'Content of Tab Pane 1' },
2: { key: '2', title: 'Feature 2', content: 'Content of Tab Pane 2' },
3: { key: '3', title: 'Feature 3', content: 'Content of Tab Pane 3' },
}
export default Navbar;
>Solution :
You defined one state for all expandable items, you should define multiple state for every item:
import { React, useState, useEffect, useCallback } from "react";
import { Tabs } from "antd";
import "antd/dist/antd.css";
const { TabPane } = Tabs;
const Navbar = (props) => {
const [inactive, setInactive] = useState(true);
const [expand1, setExpand1] = useState(false);
const [expand2, setExpand2] = useState(false);
const [expand3, setExpand3] = useState(false);
const [focusingPaneKey, setFocusingPaneKey] = useState("");
const [openingPaneKeys, setOpeningPaneKeys] = useState([]);
const openPane = (paneKey) => {
setOpeningPaneKeys((oldState) => {
if (!oldState.includes(paneKey)) {
return [...oldState, paneKey];
}
return oldState;
});
setFocusingPaneKey(paneKey);
};
const closePane = (paneKey) => {
if (paneKey === focusingPaneKey) {
const paneKeyIndex = openingPaneKeys.indexOf(paneKey);
setFocusingPaneKey(openingPaneKeys[paneKeyIndex - 1]);
}
setOpeningPaneKeys(
openingPaneKeys.filter((openingPaneKey) => openingPaneKey !== paneKey)
);
};
const handleTabsEdit = useCallback(
(key, action) => {
if (action === "remove") {
closePane(key);
}
},
[closePane]
);
useEffect(() => {
if (inactive) {
document.querySelectorAll(".sub-menu").forEach((el) => {
el.classList.remove("active");
});
}
// props.onCollapse(inactive);
}, [inactive]);
// const { panes } = props
const keysOfPane = Object.keys(panes);
return (
<>
<div className={`side-navbar ${inactive ? "inactive" : ""}`}>
<div className="top-section">
<div
onClick={() => {
setInactive(!inactive);
}}
className="menu-btn"
>
{inactive ? <i class="bx bx-menu"></i> : <i class="bx bx-x"></i>}
</div>
</div>
<div className="search-box">
<button className="search-btn">
<i class="bx bx-search"></i>
</button>
<input type="text" placeholder="search" />
</div>
<div className="divider"></div>
<div className="main-menu">
<ul>
<li>
<a onClick={() => openPane("1")} className="menu-item">
<div className="menu-icon">
<i class="bx bx-grid-alt"></i>
</div>
<span>Feature-1</span>
</a>
</li>
<li onClick={() => setExpand1(!expand1)}>
<a onClick={() => openPane("2")} className="menu-item">
<div className="menu-icon">
<i class="bx bx-grid-alt"></i>
</div>
<span>Feature-2</span>
<div className="drop-down">
<i class="bx bxs-down-arrow"></i>
</div>
</a>
<ul className={`sub-menu ${expand1 ? "active" : ""}`}>
<li>
{" "}
<a>sub-menu-1</a>{" "}
</li>
<li>
{" "}
<a>sub-menu-2</a>{" "}
</li>
<li>
{" "}
<a>sub-menu-3</a>{" "}
</li>
</ul>
</li>
{/* <MenuItem
name = {" Feature-2 "}
subMenus = {[
{name: "sub-menu-1"},{name: "sub-menu-2"},{name: "sub-menu-3"}
]}
/> */}
<li onClick={() => setExpand2(!expand2)}>
<a className="menu-item">
<div className="menu-icon">
<i class="bx bx-grid-alt"></i>
</div>
<span>Feature-3</span>
<div className="drop-down">
<i class="bx bxs-down-arrow"></i>
</div>
</a>
<ul className={`sub-menu ${expand2 ? "active" : ""}`}>
<li>
{" "}
<a>sub-menu-1</a>{" "}
</li>
<li>
{" "}
<a>sub-menu-2</a>{" "}
</li>
<li>
{" "}
<a>sub-menu-3</a>{" "}
</li>
</ul>
</li>
<li onClick={() => setExpand3(!expand3)}>
<a className="menu-item">
<div className="menu-icon">
<i class="bx bx-grid-alt"></i>
</div>
<span>Feature-4</span>
<div className="drop-down">
<i class="bx bxs-down-arrow"></i>
</div>
</a>
<ul className={`sub-menu ${expand3 ? "active" : ""}`}>
<li>
{" "}
<a>sub-menu-1</a>{" "}
</li>
<li>
{" "}
<a>sub-menu-2</a>{" "}
</li>
<li>
{" "}
<a>sub-menu-3</a>{" "}
</li>
</ul>
</li>
</ul>
</div>
</div>
<div>
<Tabs
hideAdd
onChange={openPane}
activeKey={focusingPaneKey}
type="editable-card"
onEdit={handleTabsEdit}
>
{openingPaneKeys
.map((key) => panes[key])
.map((pane) => (
<TabPane tab={pane.title} key={pane.key}>
{pane.content}
</TabPane>
))}
</Tabs>
</div>
</>
);
};
const panes = {
1: { key: "1", title: "Feature 1", content: "Content of Tab Pane 1" },
2: { key: "2", title: "Feature 2", content: "Content of Tab Pane 2" },
3: { key: "3", title: "Feature 3", content: "Content of Tab Pane 3" }
};
export default function App() {
return <Navbar />;
}