Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically adding active class to multi level sidebar menu in REACT JS

I'm currently creating a multilevel sidebar menu in REACT and I want to dynamically add active class to parent <li> when the current route is active.

The code below is how I do it for a single menu.

<Route
  path={this.props.to}
  exact={this.props.activeOnlyWhenExact}
  children={({ match }) => (
    <li className={match ? "active" : ""}>
      <Link to={this.props.to} activeClassName="active">
        <span className="sidebar-mini-icon">
          <i className={this.props.icon}></i></span>
          {this.props.label}
      </Link>
    </li>
  )}
/>

Now I wonder how I do it with multilevel menu. My menu looks like this;

enter image description here

As you can see, only the menu has the active class. Here's my code for the multi level menu:

<Route
  path={this.props.to}
  exact={this.props.activeOnlyWhenExact}
  children={({ match }) => (
  <li>
    <a data-toggle="collapse" href="#Collapse">
      <span className="sidebar-mini-icon">
        <i className={this.props.icon}></i>
      </span>
      <span className="sidebar-normal">
        {this.props.name}
        <b className="caret"></b>
      </span>
    </a>
    <div class="collapse" id="Collapse">
       <ul className="nav">
         {this.props.children}
       </ul>
    </div>
  </li>
  )}
/>

I'm using React Router. Any help will be appreciated. Thank you.

like image 380
Sonson Ixon Avatar asked Jan 06 '19 04:01

Sonson Ixon


2 Answers

The solution would depend on your route configuration. If you are using non-exact routes, the solution with NavLink would be the most applicable.

Example:

routes.jsx

<Route path="/parent/child-a">
  <ChildA />
</Route>
<Route path="/parent/child-b">
  <ChildB />
</Route>
<Route path="/parent">
  <Parent />
</Route>

Using the above structure, /parent/child-a would match two routes (/parent and /parent/child-a) and the activeClassName prop on the NavLink would be applied on both HTML element.

The "challenge" with the above structure is that you are going to render <Parent /> in all three cases.

This could be solved by using nested/child routes.

routes.jsx

<Route path="/parent">
  <NestedRoutes />
</Route>

nestedRoutes.jsx

<Route path="/parent/child-a" exact>
  <ChildA />
</Route>
<Route path="/parent/child-b" exact>
  <ChildB />
</Route>

With the updated structure above, /parent/child-a would match the top-level route (and as a result add the activeClassName to your HTML element) and also match the child route and add the activeClassName there too.

Note that if you need /parent to also work as a route, you need to update your nested routes as follows:

nestedRoutes.jsx

<Route path="/parent" exact>
  <Parent />
</Route>

From my experience, if you find yourself handling these cases manually through JavaScript or useLocation you might want to revisit your route configuration. react-router is an excellent library in its simplicity and will probably handle your case out of the box.

like image 172
Kevin Farrugia Avatar answered Oct 28 '22 08:10

Kevin Farrugia


You can use React router's nav link

<NavLink to="/faq" activeClassName="selected">
  FAQs
</NavLink>
like image 1
moshfiqrony Avatar answered Oct 28 '22 09:10

moshfiqrony