I’m building a React SPA and using react-router-dom for routing, and react-bootstrap as a component library. For a simple header, I had several goals:
- Active nav links are styled (you can tell which one you’re on, and hovering the link to the page you’re on does not show a pointer or hover style; but links to other pages do)
- Clicking the active link (or the Navbar.Brand component, when on the home page) should not reload the page you’re already on
- On mobile, clicking a nav menu item should collapse on click
- Use TypeScript
These three goals seemed very straightforward and not contradictory; but I had a hard time making them play nicely together.
The Problem
To detect the active links, the NavLink component of react-router-dom has an isActive property you can reference in an inline style, for example:
style={({ isActive }) => ({ cursor: isActive ? 'default' : 'pointer' })}
However, to get the react-bootstrap Navbar menu to collapseOnSelect, you have to use the react-bootstrap Nav.Link component, not NavLink.
You also can’t nest a Nav.Link within a NavLink; nesting <a> tags breaks the HTML standards.
I tried many iterations; getting one to work using “as” to render a different component than I specified:
<Nav.Link as={NavLink} eventKey="1" style={({ isActive }) => ({ cursor: isActive ? 'default' : 'pointer' })} to="/">
…until I tried to add TypeScript. Then it was just barking about the conflicting properties between those two definitions.
The Solution
Enter another library:
import { LinkContainer } from 'react-router-bootstrap';
Then the code was blissfully simple, working properly, and conforming to TypeScript! I had to add in the forced active={false} since both libraries apply an “active” property, which leaves multiple links appearing “active” after navigating. Best to disable the Nav.Link ones and just let LinkContainer do the work.
<Nav>
<LinkContainer to="/">
<Nav.Link active={false}>Home</Nav.Link>
</LinkContainer>
<LinkContainer to="/about">
<Nav.Link active={false}>About</Nav.Link>
</LinkContainer>
</Nav>