jansmolders86
jansmolders86

Reputation: 5759

React router Link; activeClassName not working

I have a navigation component which renders each navigation link. The return of this component looks like this:

     return (
        <li key={`nav-list-${el.title}-${index}`}>
          <Link to={{pathname: '/c/' + el.urlkey}}
                activeClassName={s.active}>{el.title}</Link>
          {subNav}
        </li>
      );

The active class is only set on a page refresh. When clicking through the links the active indicator stays at the initial link.

I'm not using Redux so it doesn't seem to be related to this issue: activeClassName does not work on the sideMenu when clicking on the link

My route look like this:

      <Route path="/c/:category(/:title)" component={CategoryView} name="category" />

using React-Router 2.8.1 and browserHistory

Upvotes: 14

Views: 43963

Answers (10)

JerSchneid
JerSchneid

Reputation: 5917

This may be dumb, but this wasn't working for me because I was importing the similarly named NavLink from reactstrap instead of react-router-dom.

I was doing this:

import { NavLink } from 'reactstrap';

But reactstrap's version of NavLink doesn't offer the activeClassName attribute.

So I switched to this:

import { NavLink } from 'react-router-dom';

Note you may have to manually add className="nav-link" to your NavLink elements to get your styles to look the same.

Upvotes: 0

Mohammadreza Abdoli
Mohammadreza Abdoli

Reputation: 1048

Please check the react-router-dom version in your project.

One difference as of v6.0.0-beta.3 is that activeClassName and activeStyle have been removed from NavLinkProps. https://reactrouter.com/en/main/components/nav-link

Instead, you can pass a function to either style or className that will allow you to customize the inline styling or the class string based on the component's active state.

Upvotes: 1

Chikwado
Chikwado

Reputation: 621

In the case that you are here because activeClassName does not work at all. Be informed that it has been deprecated starting from react-router 6. Instead use className as a function that takes a prop and return class names. as in

<NavLink className={({isActive}) => isActive ? "active-class": "non-active-class" } > </Navlink>

isActive is a boolean indicating whether the route is the current.

Reference: react router docs

Upvotes: 8

user11572942
user11572942

Reputation:

Instructions

  1. Use <NavLink> instead of <Link> and add exact as a property

  2. Include exact as a property to ensure activeClassName only triggers on url paths that match your location exactly

Example

<NavLink exact activeClassName="active" to="/path1">
<NavLink exact activeClassName="active" to="/path2">

Source

https://reacttraining.com/react-router/web/api/NavLink/exact-bool

exact: bool

When true, the active class/style will only be applied if the location is matched exactly.

Upvotes: 26

Andy
Andy

Reputation: 1080

Had the same issue! Resolved by wrapping the parent component via withRouter. E.g.

import { withRouter } from 'react-router';

class NavBar extends Component {
    ...
}

export default withRouter(NavBar);

Upvotes: 3

f.jafari
f.jafari

Reputation: 568

I was having this problem in react-router-dom v4.3. and my entire App was already wrapped using withRouter. I'm also using react-redux. I noticed that it would add class to the correct link.

const mapStateToProps = (state) => {
return {
    router: state.router,
    location: state.route.location
 }
}
export default connect(mapStateToProps, mapDispatchToProps)(Header)

and my navigation links looked like this

 <NavLink
        exact
        to="/logs"
        className="menu-item"
        activeClassName="selected"
        >
        <i className="st-icon-log-reports" /> logs 
 </NavLink>

Upvotes: 0

ShlomyN
ShlomyN

Reputation: 426

<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>

from ReactTraining did it for me

Upvotes: 2

Tom Van Rompaey
Tom Van Rompaey

Reputation: 3586

There are 2 solutions for this:

Edit: you're not using Redux so the second solution won't work.

Upvotes: 0

jansmolders86
jansmolders86

Reputation: 5759

I didn't want to upgrade just yet as it was causing more issues than it resolved. And I wasn't using Redux so the whole connect thing didn't apply. I tried render both pure and unpure (using the pure-render decorator) with no result.

So I decided to write the link handling manually. It's super verbose I know but it works!

I added the router context:

static contextTypes = {
   router: React.PropTypes.object
};

The render returns:

return (
   <li key={`nav-${el.title}`} className={`${isActiveClass}`}>
     <a onClick={this.state.LinkClick} data-item={urlkey}>{el.title}</a>
   </li>
);

The click handler looks like this:

LinkClick(e){
   e.preventDefault();
   const elem = e.currentTarget;
   const item = elem.dataset.item;
   this.context.router.push('/c/'+item);
   this.setState({
     activeLink: item
   });
 }

Finally I set the class in the render:

  const activeLink = this.state.activeLink;
  let isActiveClass = '';
  let navLinks = map(availableCategories, (el, index) => {
  const urlkey = el.urlkey;

  // Check the active item on page render
  const isActive = this.context.router.isActive('/c/' + urlkey);

  if(activeLink === urlkey || isActive){
    isActiveClass = s.active;
  } else {
    isActiveClass = '';
  }

Upvotes: 0

Piotr Berebecki
Piotr Berebecki

Reputation: 7468

It's hard to debug without seeing the complete code but problems with React Router activeClassName can often be solved by either:

  • Making sure that you have one IndexLink:

    <li><IndexLink to="/" activeClassName="active">Home</IndexLink></li> <li><Link to="/" activeClassName="active">About</Link></li> <li><Link to="/" activeClassName="active">Contact</Link></li>

  • Or using the onlyActiveOnIndex attribute on all Links:

    <li><Link to="/" activeClassName="active" onlyActiveOnIndex>Home</Link></li> <li><Link to="/" activeClassName="active" onlyActiveOnIndex>About</Link></li> <li><Link to="/" activeClassName="active" onlyActiveOnIndex>Contact</Link></li>

Here is a working demo of a second solution: http://codepen.io/PiotrBerebecki/pen/qaKqRW

Upvotes: 6

Related Questions