How to set activeClassName for wrapper element of Link or IndexLink in react-router?
37,865
Solution 1
You need to enclose your <li>
as a router aware component:
import { Link, IndexLink } from 'react-router'
class NavItem extends React.Component {
render () {
const { router } = this.context
const { index, onlyActiveOnIndex, to, children, ...props } = this.props
const isActive = router.isActive(to, onlyActiveOnIndex)
const LinkComponent = index ? Link : IndexLink
return (
<li className={isActive ? 'active' : ''}>
<LinkComponent {...props}>{children}</LinkComponent>
</li>
)
}
}
Usage:
<ul>
<NavItem to='/' index={true}>Home</NavItem>
<NavItem to='/a'>A</NavItem>
</ul>
I took inspration from the react-router-bootstrap module, https://github.com/react-bootstrap/react-router-bootstrap/blob/master/src/LinkContainer.js. I didn't test it though so let me know how it goes.
Solution 2
The other answers don't seem to work in React Router v4. Here's how you can do it:
import React, {PropTypes} from 'react'
import {Route, Link} from 'react-router-dom'
import styles from './styles.less';
export default function NavItem({children, to, exact}) {
return (
<Route path={to} exact={exact} children={({match}) => (
<li className={match ? styles.activeRoute : null}>
<Link to={to}>{children}</Link>
</li>
)}/>
)
}
NavItem.propTypes = {
to: PropTypes.string.isRequired,
exact: PropTypes.bool,
children: PropTypes.node.isRequired,
};
Solution 3
/**
* A navigation component
*/
import React, { Component } from 'react'
import { Link, IndexLink, withRouter } from 'react-router'
import styles from './styles.scss'
class NavItem extends Component {
render () {
const { router } = this.props
const { index, to, children, ...props } = this.props
let isActive
if( router.isActive('/',true) && index ) isActive = true
else isActive = router.isActive(to)
const LinkComponent = index ? IndexLink : Link
return (
<li className={isActive ? 'active' : ''}>
<LinkComponent to={to} {...props}>{children}</LinkComponent>
</li>
)
}
}
NavItem = withRouter(NavItem)
export default NavItem
Usage:
<ul className="nav nav-tabs">
<NavItem to='/home' index={true} >Home</NavItem>
<NavItem to='/about'>About</NavItem>
</ul>
Solution 4
{/* Make sure that `location` is injected into this component */}
<ul className="nav navbar-nav">
<li className={location.pathname === '/' && 'active'}>
<Link to='/'>
Home page
</Link>
</li>
<li className={location.pathname.startsWith('/about') && 'active'}>
<Link to='/about'>
About us
</Link>
</li>
</ul>
Solution 5
In stead of using <Link />
, I use <NavLink />
and It works as well.
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
//.....
export default class AppNav extends Component {
render (){
return (
<header>
<ul className="main-nav">
<li><NavLink activeClassName={"active"} exact={true} to="/">Home</NavLink></li>
<li><NavLink activeClassName={"active"} to="/about">About</NavLink></li>
<li><NavLink activeClassName={"active"} to="/courses">Courses</NavLink></li>
</ul>
</header>
);
}
}
Comments
-
abekenza almost 2 years
I am new to the ReactJS world, and would like to know how can I pass active class name to the
<li>
element instead of<a>(Link)
element.Now I have this kind of code. The anchor class changes when clicked.
<li><IndexLink to='/' activeclassName='active'>A</IndexLink></li> <li><Link to='/b' activeclassName='active'>B</Link></li> <li><Link to='/c' activeclassName='active'>C</Link></li>
But I would like to get something similar to:
<li activeclassName='active'><IndexLink to='/'>A</IndexLink></li> <li activeclassName='active'><Link to='/b'>B</Link></li> <li activeclassName='active'><Link to='/c'>C</Link></li>
Thanks in advance
-
Nick over 7 yearsAlthough it looks similar to Marc's answer on first glance, this answer worked better for me.
withRouter
seems to be the way in current versions to get access to the router. -
CLaff over 7 yearsThis worked for me but since i was using a IndexLink i had make this one change: else isActive = router.isActive(to, true) . I had to add true to IsActive function or else isActive always returned true for '/'.
-
Kushal Shah over 7 yearsDepending on your setup, you may need
NavLi.contextTypes = { router: React.PropTypes.object }; export default NavLi;
-
Uchenna about 7 yearsEasiest answer.
-
Tran Dinh Khanh about 7 yearsThank you for this. I would add
...props
to params and use it in<Link to={to} {...props}>{children}</Link>
for more flexible. -
GajananB about 7 yearsYou may need to ensure your component gets the context e.g.
router: PropTypes.object.isRequired
-
Travis Watson almost 7 yearsInstead of getting
router
through the context, use thewithRouter
HOC fromreact-router
package to get the router via props. This will also update the link's active status when the page changes, since otherwise React has no way to know if theisActive
has changed. -
dano over 6 yearsThis fixed my issue. I wonder what the difference is between them that makes it work?
-
Sagiv b.g over 6 yearsi would not use the ternary operator and instead use this
<li className={match && styles.activeRoute}>
more terse. -
mpen over 6 years@Sag1v I don't like using that syntax anymore. I got bit when it evaluated to
0
and I had a stray 0 in my UI. Can create even worse bugs if you're not careful. -
Sagiv b.g over 6 years@mpen i know what you mean, though in this case a
0
would produce the same effect won't it? -
Derek over 6 yearsDid not worked:
router
is undefined for me, not found inthis.props
:-( -
Tmh over 6 yearsWorked for me, no need of any workarounds, Should mark it as the best answer.
-
Tobbe over 6 yearsUpdated jsfiddle for the answer @mpen gave above: jsfiddle.net/69z2wepo/99537
-
Abhisek Mishra about 6 yearsIs it setting the class of parent
<li>
element ? For me it is just setting the class of<a>
that is created from<NavLink>
. -
Goran Jakovljevic over 5 yearsThis wasnt the question. He asked about parent class.
-
Bastian Voigt over 5 years
withRouter(...)
does not work for me.this.context.router
is still undefined :( -
Zerquix18 over 5 yearsThis component doesn't re-render when the route changes, so it'll only become active for the first render
-
mpen over 5 years@Zerquix18 Sounds like a bug in your code. Did you put a
PureComponent
somewhere further up the tree perhaps? ThisNavItem
is an SFC, there isn't any logic to prevent a re-render. -
Aaron C almost 4 yearsThe OP wants to add the class to the parent element of the Link, not the Link itself.
-
guijob about 3 yearsfor react router v5 you should use ` <li className={match.path === to ? styles.activeRoute : null}>`