[react-router] How do I add an active class to a Link from React Router?

I've created a bootstrap-style sidebar using Link. Here is a snippet of my code:

<ul className="sidebar-menu">
  <li className="header">MAIN NAVIGATION</li>
  <li><Link to="dashboard"><i className="fa fa-dashboard"></i> <span>Dashboard</span></Link></li>
  <li><Link to="email_lists"><i className="fa fa-envelope-o"></i> <span>Email Lists</span></Link></li>
  <li><Link to="billing"><i className="fa fa-credit-card"></i> <span>Buy Verifications</span></Link></li>
</ul>

I want to set the class for the active path to active on the wrapping element <li>. I see there are other solutions out there that show how to do this like Conditionally set active class on menu using react router current route, however I don't think that it's the best way to set an active class on a wrapper to a Link.

I also found https://github.com/insin/react-router-active-component but it feels like it is unnecessary.

In React Router, is this possible or do I need to use an external solution?

This question is related to react-router

The answer is


Using Jquery for active link:

$(function(){
    $('#nav a').filter(function() {
        return this.href==location.href
    })
    .parent().addClass('active').siblings().removeClass('active')

    $('#nav a').click(function(){
        $(this).parent().addClass('active').siblings().removeClass('active')
    })
});

Use Component life cycle method or document ready function as specified in Jquery.


Since router v4 I am using 'refs' for setting the parent active class:

<ul>
  <li>
    <NavLink
      innerRef={setParentAsActive}
      activeClassName="is-active"
      to={link}
    >
    {text}
  </NavLink>
</ul>

NavLink's innerRef prop accepts callback function, which will receive DOM node as an argument. You can use then any DOM manipulation possible, in this case simply set parent element (<li>) to have the same class:

  const setParentAsActive = node => {
    if (node) {
      node.parentNode.className = node.className;
    }
  };

Drawbacks:

  • <a> will have unnecessary is-active class (as you only need it for <li>), or you can remove this class in the callback func.
  • if you change the element structure, f.e. wrap a tag inside a span, your callback will stop working, but it's possible to write more sofisticated DOM traverse function
  • you have to do some DOM manipulation

React-Router V4 comes with a NavLink component out of the box

To use, simply set the activeClassName attribute to the class you have appropriately styled, or directly set activeStyle to the styles you want. See the docs for more details.

<NavLink
  to="/hello"
  activeClassName="active"
>Hello</NavLink>

Its very easy to do that, react-router-dom provides all.

_x000D_
_x000D_
import React from 'react';_x000D_
import { matchPath, withRouter } from 'react-router';_x000D_
    _x000D_
class NavBar extends React.Component {_x000D_
  render(){_x000D_
    return(_x000D_
       <ul className="sidebar-menu">_x000D_
      <li className="header">MAIN NAVIGATION</li>_x000D_
      <li className={matchPath(this.props.location.pathname, { path: "/dashboard" }) ? 'active' : ''}><Link to="dashboard"><i className="fa fa-dashboard"></i> _x000D_
        <span>Dashboard</span></Link></li>_x000D_
      <li className={matchPath(this.props.location.pathname, { path: "/email_lists" }) ? 'active' : ''}><Link to="email_lists"><i className="fa fa-envelope-o"></i> _x000D_
        <span>Email Lists</span></Link></li>_x000D_
      <li className={matchPath(this.props.location.pathname, { path: "/billing" }) ? 'active' : ''}><Link to="billing"><i className="fa fa-credit-card"></i> _x000D_
        <span>Buy Verifications</span></Link></li>_x000D_
    </ul>_x000D_
      )_x000D_
   }_x000D_
}_x000D_
    _x000D_
export default withRouter(NavBar);
_x000D_
_x000D_
_x000D_

Wrapping You Navigation Component with withRouter() HOC will provide few props to your component: 1. match 2. history 3. location

here i used matchPath() method from react-router to compare the paths and decide if the 'li' tag should get "active" class name or not. and Im accessing the location from this.props.location.pathname.

changing the path name in props will happen when our link is clicked, and location props will get updated NavBar also get re-rendered and active style will get applied


Current React Router Version 5.2.0

activeStyle is a default css property of NavLink component which is imported from react-router-dom

So that we can write our own custom css to make it active.In this example i made background transparent and text to be bold.And I store it on a constant named isActive

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

    function nav() {

          const isActive = {
            fontWeight: "bold",
            backgroundColor: "rgba(255, 255, 255, 0.1)",
          };
    
    return (
          <ul className="navbar-nav mr-auto">
            <li className="nav-item">
              <NavLink className="nav-link" to="/Shop" activeStyle={isActive}>
                Shop
              </NavLink>
            </li>
          </ul>
          );

    export default nav;


Expanding on @BaiJiFeiLong's answer, add an active={} property to the link:

<Nav.Link as={Link} to="/user" active={pathname.startsWith('/user')}>User</Nav.Link>

This will show the User link as active when any path starts with '/user'. For this to update with each path change, include withRouter() on the component:

import React from 'react'
import { Link, withRouter } from 'react-router-dom'
import Navbar from 'react-bootstrap/Navbar'
import Nav from 'react-bootstrap/Nav'

function Header(props) {
    const pathname = props.location.pathname

    return (
        <Navbar variant="dark" expand="sm" bg="black">
            <Navbar.Brand as={Link} to="/">
                Brand name
            </Navbar.Brand>
            <Navbar.Toggle aria-controls="basic-navbar-nav" />
            <Navbar.Collapse id="basic-navbar-nav">
                <Nav className="mr-auto">
                    <Nav.Link as={Link} to="/user" active={pathname.startsWith('/user')}>User</Nav.Link>
                    <Nav.Link as={Link} to="/about" active={pathname.startsWith('/about')}>About</Nav.Link>
                </Nav>
            </Navbar.Collapse>
        </Navbar>
    )
}

export default withRouter(Header)   // updates on every new page

For me what worked has is using NavLink as it has this active class property.

  1. First import it

    import { NavLink } from 'react-router-dom';
    
  2. Use an activeClassName to get the active class property.

    <NavLink to="/" activeClassName="active">
     Home
    </NavLink>
    
    <NavLink to="/store" activeClassName="active">
     Store
    </NavLink>
    
    <NavLink to="/about" activeClassName="active">
     About Us
    </NavLink>
    
  3. Style your class in the css by the property active.

    .active{
      color:#fcfcfc;
     }
    

This is my way, using location from props. I don't know but history.isActive got undefined for me

export default class Navbar extends React.Component {
render(){
const { location } = this.props;

const homeClass = location.pathname === "/" ? "active" : "";
const aboutClass = location.pathname.match(/^\/about/) ? "active" : "";
const contactClass = location.pathname.match(/^\/contact/) ? "active" : "";


return (
<div>
      <ul className="nav navbar-nav navbar-right">
        <li className={homeClass}><Link to="/">Home</Link></li>
        <li className={aboutClass}><Link to="about" activeClassName="active">About</Link></li>
        <li className={contactClass}><Link to="contact" activeClassName="active">Contact</Link></li>
      </ul>

</div>
    );}}

Use React Hooks.

import React, { useState } from 'react';

export const Table = () => {

const [activeMenu, setActiveMenu] = useState('transaction');

return(
<>
 <Link className="flex-1 mr-2">
          <a
            id="transaction"
            className={
              activeMenu == 'transaction'
                ? 'text-center block border border-blue-500 rounded py-2 px-4 bg-blue-500 hover:bg-blue-700 text-white'
                : 'text-center block border border-white rounded hover:border-gray-200 text-blue-500 hover:bg-gray-200 py-2 px-4'
            }
            href="#"
            onClick={() => {
              setActiveMenu('transaction');
            }}>
            Recent Transactions
          </a>
        </Link>
        <Link className="flex-1 mr-2">
          <a
            id="account"
            className={
              activeMenu == 'account'
                ? 'text-center block border border-blue-500 rounded py-2 px-4 bg-blue-500 hover:bg-blue-700 text-white'
                : 'text-center block border border-white rounded hover:border-gray-200 text-blue-500 hover:bg-gray-200 py-2 px-4'
            }
            href="#"
            onClick={() => {
              setActiveMenu('account');
            }}>
            Account Statement
          </a>
        </LInk>

</>
)
}

One of the way you can use it

When you are using the Functional component then follow the instruction here.

  • add a variable in your component
  • create an event change browser URL change/or other change
  • re-assign the current path (URL)
  • use javascript match function and set active or others

Use the above code here.

import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';

const NavItems = () => {
    let pathname = window.location.pathname;
    useEffect(() => {
        pathname = window.location.pathname;
    }, [window.location.pathname]);

    return (
        <>
            <li className="px-4">
                <Link to="/home" className={`${pathname.match('/home') ? 'link-active' : ''}`}>Home</Link>
            </li>
            <li className="px-4">
                <Link to="/about-me" className={`${pathname.match('/about-me') ? 'link-active' : ''}`}>About-me</Link>
            </li>
            <li className="px-4">
                <Link to="/skill" className={`${pathname.match('/skill') ? 'link-active' : ''}`}>Skill</Link>
            </li>
            <li className="px-4">
                <Link to="/protfolio" className={`${pathname.match('/protfolio') ? 'link-active' : ''}`}>Protfolio</Link>
            </li>
            <li className="pl-4">
                <Link to="/contact" className={`${pathname.match('/contact') ? 'link-active' : ''}`}>Contact</Link>
            </li>
        </>
    );
}

export default NavItems;

--- Thanks ---


To set class on the active navigation element

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

&

<NavLink to="/Home" activeClassName="active">Home</NavLink>


On the Link component you can now add activeClassName or set activeStyle.

These allow you to easily add styles to the currently active link.


Previously, you could create a custom component that works like a wrapper to Link with the following logic.

In a file called nav_link.js

import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';

class NavLink extends React.Component {
    render() {
        var isActive = this.context.router.route.location.pathname === this.props.to;
        var className = isActive ? 'active' : '';

        return(
            <Link className={className} {...this.props}>
                {this.props.children}
            </Link>
        );
    }
}

NavLink.contextTypes = {
    router: PropTypes.object
};

export default NavLink;

And use it as given below in your component:

...
import NavLink from "./nav_link";
.....

<nav>
    <ul className="nav nav-pills pull-right">
        <NavLink to="/">
            <i className="glyphicon glyphicon-home"></i> <span>Home</span>
        </NavLink>
        <NavLink to="about">
            <i className="glyphicon glyphicon-camera"></i> <span>About</span>
        </NavLink>
    </ul>
</nav>

The answer by Vijey has a bit of a problem when you're using react-redux for state management and some of the parent components are 'connected' to the redux store. The activeClassName is applied to Link only when the page is refreshed, and is not dynamically applied as the current route changes.

This is to do with the react-redux's connect function, as it suppresses context updates. To disable suppression of context updates, you can set pure: false when calling the connect() method like this:

//your component which has the custom NavLink as its child. 
//(this component may be the any component from the list of 
//parents and grandparents) eg., header

function mapStateToProps(state) {
  return { someprops: state.someprops }
}

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

Check the issue here: reactjs#470

Check pure: false documentation here: docs


Just use NavLink rather than Link. It will add .active class automatically.

<Nav className="mr-auto">
    <Nav.Link as={NavLink} to="/home">Home</Nav.Link>
    <Nav.Link as={NavLink} to="/users">Users</Nav.Link>
</Nav>

_x000D_
_x000D_
import React from 'react';_x000D_
import {withRouter, Link} from "react-router-dom";_x000D_
_x000D_
const SidenavItems = (props) => {_x000D_
                                     // create simple list of links_x000D_
    const items = [_x000D_
        {_x000D_
            type: "navItem",_x000D_
            icon: "home",_x000D_
            text: "Home",_x000D_
            link: "/",_x000D_
            restricted: false_x000D_
        },_x000D_
        {_x000D_
            type: "navItem",_x000D_
            icon: "user-circle",_x000D_
            text: "My Profile",_x000D_
            link: "/user",_x000D_
            restricted: false_x000D_
        },_x000D_
        {_x000D_
            type: "navItem",_x000D_
            icon: "sign-in",_x000D_
            text: "Login",_x000D_
            link: "/login",_x000D_
            restricted: false_x000D_
        },_x000D_
    ];_x000D_
_x000D_
    const element = (item, i) => {  // create elements (Links)_x000D_
                        // check if this is a current link on browser_x000D_
        let active = "";_x000D_
_x000D_
        if (props.location.pathname === item.link) {_x000D_
            active = "active";_x000D_
        }_x000D_
_x000D_
        return (_x000D_
            <div key={i} className={item.type}>_x000D_
                <Link_x000D_
                    to={item.link}_x000D_
                    className={active} // className will be set to "active" _x000D_
                >                      // or ""_x000D_
                    {item.text}_x000D_
                </Link>_x000D_
            </div>_x000D_
        )_x000D_
    };_x000D_
_x000D_
    const showItems = () => {     // print elements_x000D_
        return items.map((item, i) => {_x000D_
            return element(item, i)_x000D_
        })_x000D_
    };_x000D_
_x000D_
    return (_x000D_
        <div>_x000D_
            {showItems()}  // print all the links we created in list_x000D_
        </div>_x000D_
    )_x000D_
};_x000D_
export default withRouter(SidenavItems);
_x000D_
_x000D_
_x000D_


With [email protected] (though any 4.x.x should do I guess), we can use the withRouter HOC to accomplish this. For example, I want to implement the Bootstrap navbar and since it requires a class of active on <li class="nav-item"> and not on the anchor tag, I made a new component called NavItem to encapsulate a single li.nav-item. The implementation is as follows:

import React from "react";
import { Link, withRouter } from "react-router-dom";

const NavItem = ({ isActive, to, label }) => {
  let classes = ["nav-item"];
  if (isActive) classes.push("active");

  return (
    <li className={classes.join(" ")}>
      <Link className="nav-link" to={to}>
        {label}
      </Link>
    </li>
  );
};

export default withRouter(({ location, ...props }) => {
  const isActive = location.pathname === props.to;

  console.log(location.pathname, props.to);

  return <NavItem {...props} isActive={isActive} />;
});

As you can see, NavItem is just a stateless functional component which expects an isActive prop to determine whether active class should be added. Now, to update this prop as the location changes, we can make use of the withRouter HOC. You can pass any component to this function and it'll give it { match, location, history } objects in its props along with the ones you pass down. Here, I am creating a functional component inline which receives these objects and determines whether the current link is the active one using the location.pathname property. This'll give us a Boolean and we can return the NavItem along with isActive set to the value we computed using location.pathname.

A working example of this can be found here. Please let me know if there's an easier way to do this.


As of [email protected], we can just easily use the NavLink with activeClassName instead of Link. Example:

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

class NavBar extends Component {
  render() {
    return (
      <div className="navbar">
        <ul>
          <li><NavLink to='/1' activeClassName="active">1</NavLink></li>
          <li><NavLink to='/2' activeClassName="active">2</NavLink></li>
          <li><NavLink to='/3' activeClassName="active">3</NavLink></li>
        </ul>
      </div>
    );
  }
}

Then in your CSS file:

.navbar li>.active {
  font-weight: bold;
}

The NavLink will add your custom styling attributes to the rendered element based on the current URL.

Document is here


I didn't like the idea of creating a custom component, because if you have a different wrapping element you would have to create another custom component etc. Also, it is just overkill. So I just did it with css and activeClassName:

<li className="link-wrapper">  <!-- add a class to the wrapper -->
  <Link to="something" activeClassName="active">Something</Link>
</li>

And then just add some css:

li.link-wrapper > a.active {
    display: block;
    width: 100%;
    height:100%;
    color: white;
    background-color: blue;
}

Technically this doesn't style the li, but it makes the anchor fill the li and styles it.


Answer updated with ES6:

import React, { Component } from 'react';
import { Link } from 'react-router'

class NavLink extends Component {
    render() {
        let isActive = this.context.router.isActive(this.props.to, true);
        let className = isActive ? "active" : "";

        return (
            <li className={className}>
                <Link {...this.props}/>
            </li>
        );
    }
}

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

export default NavLink;

Then use it as described above.


You can actually replicate what is inside NavLink something like this

const NavLink = ( {
  to,
  exact,
  children
} ) => {

  const navLink = ({match}) => {

    return (
      <li class={{active: match}}>
        <Link to={to}>
          {children}
        </Link>
      </li>
    )

  }

  return (
    <Route
      path={typeof to === 'object' ? to.pathname : to}
      exact={exact}
      strict={false}
      children={navLink}
    />
  )
}

just look into NavLink source code and remove parts you don't need ;)