38

I am using react-router-dom: 4.2.2. I can add activeClassName to the current URL. But surprisingly the class is always added to root URL.

While visiting a page, for example the error page like the screenshot below, the home navlink also getting the activeClass.

enter image description here

Update: In the above screenshot I have showed that I visited http://localhost:3000/#/error. So, the active-link should be added to the Love Error? NavLink only. But as you can see it is also added to Home NavLink too.

Here is my navbar code:

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

export const NavigationBar = () => (
  <ul className="horizontal-menu">
    <li> <NavLink to = '/' activeClassName="active-link">Home</NavLink> </li>
    <li> <NavLink to = '/about' activeClassName="active-link">About Us</NavLink> </li>
    <li> <NavLink to = '/error' activeClassName="active-link">Love Error?</NavLink> </li>
  </ul>
)

For routing I have used the following Switch:

<Switch>
  <Route exact path = '/' component = {Home} />
  <Route exact path = '/about' component = {AboutUs} />
  <Route exact path = '/error' component = {Error404} />
  <Route path = "/news/:id" component = {NewsDetail} />
  <Route path="*" component={Error404} />
</Switch>

How can I get the expected behavior?

arshovon
  • 13,270
  • 9
  • 51
  • 69

10 Answers10

53

You have to use isActive={} to add additional verification to ensure whether the link is active.

document

Working jsFiddle. (fiddle is not created by me)

Code you need to add is like below

Example in jsfiddle

<li><NavLink to="/" isActive={checkActive}>Home</NavLink></li>

Change in your code

<li> <NavLink to='/' activeClassName="active-link" isActive={checkActive}>Home</NavLink> </li>

check the isActive prop and "checkActive" is a function.

const checkActive = (match, location) => {
    //some additional logic to verify you are in the home URI
    if(!location) return false;
    const {pathname} = location;
    console.log(pathname);
    return pathname === "/";
}

Another config you can use is "exact" but It is not possible to demonstrate it in a jsFiddle. I think the code would be like

<li> <NavLink exact to='/' activeClassName="active-link">Home</NavLink> </li>

Hope this helps. And let me know if you need more info.

vsync
  • 118,978
  • 58
  • 307
  • 400
Shashith Darshana
  • 2,715
  • 1
  • 25
  • 27
48

I've found that adding exact before the first activeClassName works as well. So for example, your set up can be:

export const NavigationBar = () => (
  <ul className="horizontal-menu">
    <li><NavLink to='/' exact activeClassName="active-link">Home</NavLink> 
    </li>
    ....remaining NavLinks
  </ul>
)
Pang
  • 9,564
  • 146
  • 81
  • 122
digitalh2o
  • 621
  • 5
  • 6
  • Sometimes, if you have additional data in the URL for example some filters, then it won't really work. The best solution then is to have a function that will decide about that. That's why the answer above is selected. – nightspite May 11 '21 at 07:45
18

You can use exact keyword for active class such as

<NavLink exact to ='/'>Home</NavLink>

it will generate like that

<a href="/" class="active" aria-current="page">Home</a>

and if you will get another page then it will be like that

<a href="/">Home</a>
fool-dev
  • 7,671
  • 9
  • 40
  • 54
5

The correct answer in 2022 is to use the end prop.

<NavLink end {...props} />

As per the docs:

If the end prop is used, it will ensure this component isn't matched as "active" when its descendant paths are matched. For example, to render a link that is only active at the website root and not any other URLs, you can use

<NavLink to="/" end>
  Home
</NavLink>

Reference: https://reactrouter.com/en/v6.3.0/api

Andrew
  • 2,691
  • 6
  • 31
  • 47
3

Working fine for me

<ul className="menu nav navbar-nav">
      <li><NavLink exact to="/" activeClassName="active-link active2">Home</NavLink></li>
      <li><NavLink to="/financial-summary" activeClassName="active-link active2">Financial Summary</NavLink></li>
      <li><NavLink to="/account-statement" activeClassName="active-link active2">Account Statement</NavLink></li>
      <li><NavLink to="/tools" activeClassName="active-link active2">Tools</NavLink></li>
      <li><NavLink to="/service-charges" activeClassName="active-link active2">Service Charges & Important Information</NavLink></li>
    </ul>

css

.active2, .active2 a:link, .active2 a:visited{
    background: #004B8D !important;
    color: #FFFFFF !important;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
}
Pankaj Upadhyay
  • 2,114
  • 21
  • 22
2

I recently came across this issue and solved it by simply adding:

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

and then wrapped the component with:

export default withRouter(Component);
Jango17
  • 21
  • 2
2

Change in your code

<li> <NavLink to='/' activeClassName="active-link" isActive={checkActive}>Home</NavLink> </li>

and then

const checkActive = (match, location) => {
  console.log(location);
  if (!location) return false;
  const { pathname } = location;
  const { url } = match;
  return pathname === url ? true : false;
};
  • note *
const { pathname } = location;
const { url } = match;
return pathname === url ? true : false;
kamalesh biswas
  • 883
  • 8
  • 9
0

I am learning React now and just came across the same problem. I tried the following and it worked for me.

So, I have 3 navigational links.

<li><NavLink to="/home">Home</NavLink></li>
<li><NavLink to="/about">About</NavLink></li>
<li><NavLink to="/contact">Contact</NavLink></li>

But I added 4 routes.

<Route exact path="/" component={Home}></Route>
<Route path="/home" component={Home}></Route>
<Route path="/about" component={About}></Route>
<Route path="/contact" component={Contact}></Route>

I added 2 routes (/ and /home) for the same component (Home). This way, the react-router-dom seems to add the class 'active' only to the link that you click.

0

If you're trying to use <Navlink> on single page website and anchor-links, make sure to replace <BrowserRouter> with <HashRouter>!

I had to remove the slash to reach my anchor text: <HashRouter hashType='noslash'>

With this setup,

<li><NavLink to="about">About</NavLink></li>

will render

<a href="#about" aria-current="page" class="active">About</a>

Documentation

flow2000
  • 21
  • 1
  • 3
-1

I am using LinkContainer from react-router-bootstrap, I was still having an issue like this. The home link was always active.

I have solved it by using an exact keyword for the path of the link like this. I hope if you will use this and have any issue regarding this, so it can help. cheers.

Header.js component :

  <LinkContainer to="/" exact>
     <Nav.Link>
       <i className="fas fa-home mr-1"></i>Home
     </Nav.Link>
  </LinkContainer>

and App.js component :

 <Route path="/" component={HomeScreen} exact />
 <Route path="/about" component={AboutScreen} exact />
 <Route path="/blogs" component={BlogScreen} exact />