Reputation: 5759
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
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
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
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
Reputation:
Use <NavLink>
instead of <Link>
and add exact as a property
Include exact
as a property to ensure activeClassName
only triggers on url paths that match your location exactly
<NavLink exact activeClassName="active" to="/path1">
<NavLink exact activeClassName="active" to="/path2">
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
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
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
Reputation: 426
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
from ReactTraining did it for me
Upvotes: 2
Reputation: 3586
There are 2 solutions for this:
v3.0.0
(released
today) where this issue is fixed. (see https://github.com/ReactTraining/react-router/issues/3286#issuecomment-220861601)v2.8.1
from this answer: https://stackoverflow.com/a/40126703Edit: you're not using Redux so the second solution won't work.
Upvotes: 0
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
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