Reputation: 163
I am trying to get a link to have the active
class when clicked in next.js
and react-bootstrap
. Upon page load, the currently active route's link is not given the active class. When I click on the link after page load, then it is given the active
class. I suspect that this has something to do with server-side rendering. Here is my code:
const Navigation = () => (
<Navbar bg="warning" variant="light" collapseOnSelect expand="lg">
<Link passHref href="/">
<Navbar.Brand>...</Navbar.Brand>
</Link>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="ml-auto">
<Link href="/">
<Nav.Link href="/" as="a">
Home
</Nav.Link>
</Link>
</Nav>
</Navbar.Collapse>
</Navbar>
);
export default Navigation;
Upon page load:
After clicking link manually:
Is there a way to make the link highlighted on the server (without a hacky solution)?
Upvotes: 0
Views: 3001
Reputation: 8238
As I know, so far there is no built-in feature like that whether in NextJS or react-bootstrap.
The example below is not a hacky solution, it is the best practice introduced by NextJS.
You need to use a class to show an active link, then have this function to check if the current url is same as the url in next/router:
import { useRouter } from 'next/router'
import PropTypes from 'prop-types'
import Link from 'next/link'
import React, { Children } from 'react'
const ActiveLink = ({ children, ...props }) => {
const { asPath } = useRouter()
const child = Children.only(children)
const childClassName = child.props.className || ''
// pages/index.js will be matched via props.href
// pages/about.js will be matched via props.href
// pages/[slug].js will be matched via props.as
const className =
asPath === props.href || asPath === props.as
? `${childClassName} active`.trim()
: childClassName
return (
<Link {...props}>
{React.cloneElement(child, {
className: className || null,
})}
</Link>
)
}
ActiveLink.propTypes = {
activeClassName: PropTypes.string.isRequired,
}
export default ActiveLink
Then in your component:
const Navigation = () => (
<Navbar bg="warning" variant="light" collapseOnSelect expand="lg">
<Link passHref href="/">
<Navbar.Brand>...</Navbar.Brand>
</Link>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="ml-auto">
<Link href="/">
<ActiveLink href="/">
<Nav.Link href="/" as="a">
Home
</Nav.Link>
</ActiveLink>
</Link>
</Nav>
</Navbar.Collapse>
</Navbar>
);
export default Navigation;
Upvotes: 3