How can I style active Link in react-router v4?

JavascriptReactjsReact RouterReact Router-V4

Javascript Problem Overview


In react-router v3 we had activeStyle and activeClassName to style active Link

we could do something like this

  <div id="tags-container">
    {tags.map(t =>
      <Link
        className="tags"
        activeStyle={{ color: 'red' }}
        to={t.path}
      >
        {t.title}
      </Link>
    )}
  </div>

I wanna know how can I do same thing in v4?

Javascript Solutions


Solution 1 - Javascript

Use NavLink instead Link. Its not documented, but its work as you expect. https://github.com/ReactTraining/react-router/issues/4318

UPDATE 17.05.2017:

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

Solution 2 - Javascript

You can do it with NavLink in react-router v4

 <div id="tags-container">
   {tags.map(t =>
     <NavLink
       className="tags"
       activeStyle={{ color: 'red' }}
       to={t.path}
     >
       {t.title}
     </NavLink>
   )}
 </div>

Solution 3 - Javascript

> If you are encountering an issue where your Nav menu works except it's not updating properly when you click links and the route changes, but it works fine if you press F5, you can do this:

This is probably occurring because you are using Redux which has a shouldComponentUpdate Lifecycle method on its connect function. You probably have your Nav component wrapped in connect. This is all good. shouldComponentUpdate is what is ruining your life.

To fix, just bring the router into your mapStateToProps function:

// This lets shouldComponentUpdate know that the route changed,
// which allows the Nav to re-render properly when the route changes, woot!
const mapStateToProps = (state) => {
  return {
    router: state.router,
  }
}

// or, if you prefer pro style destructure shorthand:
const mapStateToProps = ({ router }) => ({ router })

If you aren't quite sure where state.router comes from, it comes from the file you combine your reducers in, and you will see something like this:

import { combineReducers } from 'redux'
import { routerReducer } from 'react-router-redux'
import authReducer from './components/auth/auth_reducer'

export default combineReducers({
  router: routerReducer,
  auth: authReducer,
})

Here is some HTML and CSS for a pretty baller Nav Link:

> HTML

<ul id="Nav_menu">
  <li>
    <NavLink
      to="/home"
      className="Nav_link"
      activeClassName="activeRoute"
      activeStyle={{ color: 'teal' }}
    >
      HOME
    </NavLink>
  </li>
  <li>
    <NavLink
    to="/products"
    className="Nav_link"
    activeClassName="activeRoute"
    activeStyle={{ color: 'teal' }}
    >
      PRODUCTS
    </NavLink>
  </li>
</ul>

NOTE: If you are linking to "/", put exact prop on NavLink.

> CSS

#Nav_menu {
  display: flex;
  flex-direction: row;
  width: 100%;
  height: 100%;
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.Nav_link:link {
  color: #fff;
  font-size: 1.6rem;
  line-height: 1.6rem;
  text-decoration: none;
}
.Nav_link:visited {
  color: #fff;
}
.Nav_link:hover {
  color: yellow;
}
.Nav_link:active {
  color: teal;
}

.activeRoute {
  background-color: yellow;
  border-bottom: 0.4rem solid teal;
  cursor: not-allowed;
}

Notice activeStyle in the HTML markup. This was the only way I could change the color of the text on the active route/link. It didn't work when I put color: teal; in the activeRoute CSS Class. Open this in another tab: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/NavLink.md

If you don't know why I used rem instead of px. This is a great opportunity for you to research web accessibility and base font-size: 10px;.

Stay fit and have fun.

Solution 4 - Javascript

This example from the react-router v4 custom link documentation will help you to accomplish it:

const OldSchoolMenuLink = ({ label, to, activeOnlyWhenExact }) => (
  <Route path={to} exact={activeOnlyWhenExact} children={({ match }) => (
    <div className={match ? 'active' : ''}>
      {match ? '> ' : ''}<Link to={to}>{label}</Link>
    </div>
  )}/>
);

So in your case you could create following component:

const CustomLink = ({ activeStyle, children, className, to, activeOnlyWhenExact }) => (
  <Route path={to} exact={activeOnlyWhenExact} children={({ match }) => (
    <Link to={to} className={className} style={match && activeStyle}>{children}</Link>
  )}/>
);

And then use it like:

  <div id="tags-container">
    {tags.map(t =>
      <CustomLink
        className="tags"
        activeStyle={{ color: 'red' }}
        to={t.path}
      >
        {t.title}
      </CustomLink>
    )}
  </div>

Solution 5 - Javascript

Expanding on @agm1984's answer: The solution of NavLinks is not updating styles correctly, which was using routerReducer from react-router-redux, has not worked for me. Instead, I found out that the issue was that connect wrapper uses shouldComponentUpdate and prevented rerendering of the component containing NavLinks.

Correct solution in my situation was to pass options object to connect as 4th parameter as shown below:

export default connect(mapStateToProps, null, null, { pure: false })(NavItems);

Solution 6 - Javascript

All still works the same. However, react-router-dom v4 replace Link with NavLink

import { NavLink as Link } from 'react-router-dom'; is also fine. Note: Navlinks by default is active so you can style a:active or activeStyle={{color: 'red'}}

Solution 7 - Javascript

React Router v6:

Source: Active NavLink Classes with React Router

I know this was a question for v4 but since v6 is released we can accomplish this now by using className property which now accepts a function and passes an isActive boolean property, like this:

<NavLink
  to="users"
  className={({ isActive }) => (isActive ? 'active' : 'inactive')}
>
  Users
</NavLink>

You can also add multiple classes too, since v6 is out:

<NavLink
  to="users"
  className={({ isActive }) =>
    isActive ? 'bg-green-500 font-bold' : 'bg-red-500 font-thin'
  }
>
  Users
</NavLink>

Demo: Active NavLink Classes with React Router

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRamtin KhalatbariView Question on Stackoverflow
Solution 1 - JavascriptSergey ReutskiyView Answer on Stackoverflow
Solution 2 - JavascriptGapur KassymView Answer on Stackoverflow
Solution 3 - Javascriptagm1984View Answer on Stackoverflow
Solution 4 - JavascriptglennreyesView Answer on Stackoverflow
Solution 5 - JavascriptMrSegFaultyView Answer on Stackoverflow
Solution 6 - JavascriptAlisher MusurmonvView Answer on Stackoverflow
Solution 7 - JavascriptChilaxathorView Answer on Stackoverflow