95

I'm having some styling issues using react-router and react-bootstrap. below is a snippet of the code

import { Route, RouteHandler, Link } from 'react-router';
import AuthService from '../services/AuthService'
import { Button, Nav, Navbar, NavDropdown, MenuItem, NavItem } from 'react-bootstrap';

    <Nav pullRight>
      <NavItem eventKey={1}>
        <Link to="home">Home</Link>
      </NavItem>
      <NavItem eventKey={2}>
        <Link to="book">Book Inv</Link>
      </NavItem>
      <NavDropdown eventKey={3} title="Authorization" id="basic-nav-dropdown">
        <MenuItem eventKey="3.1">
          <a href="" onClick={this.logout}>Logout</a>
        </MenuItem>          
      </NavDropdown>  
    </Nav>

This is what it looks like when it renders.

enter image description here

I know that the <Link></Link> is causing this but I don't know why? I would like for this to be in-line.

chad schmidt
  • 1,022
  • 1
  • 10
  • 8

10 Answers10

254

Using LinkContainer from react-router-bootstrap is the way to go. The following code should work.

import { Route, RouteHandler, Link } from 'react-router';
import AuthService from '../services/AuthService'
import { Button, Nav, Navbar, NavDropdown, MenuItem, NavItem } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';

/// In the render() method
<Nav pullRight>
  <LinkContainer to="/home">
    <NavItem eventKey={1}>Home</NavItem>
  </LinkContainer>
  <LinkContainer to="/book">
    <NavItem eventKey={2}>Book Inv</NavItem>
  </LinkContainer>
  <NavDropdown eventKey={3} title="Authorization" id="basic-nav-dropdown">
    <LinkContainer to="/logout">
      <MenuItem eventKey={3.1}>Logout</MenuItem>    
    </LinkContainer>      
  </NavDropdown>  
</Nav>

This is mostly a note to future self, when googling this issue. I hope someone else might benefit from the answer.

Gennon
  • 2,669
  • 1
  • 13
  • 12
  • 38
    +1: The [official recommendation from react-bootstrap, and react-router](https://github.com/reactjs/react-router/issues/83#issuecomment-214794477), is to use [react-router-bootstrap](https://github.com/react-bootstrap/react-router-bootstrap). – Brett Sun Jun 16 '16 at 09:53
  • 4
    how about toggling the activeClassName? – Anyul Rivas Aug 28 '16 at 07:19
  • If you cannot make this work, just make sure your path is included in React Router. – Anant Simran Singh Sep 23 '16 at 12:32
  • Jeez, wasted an hour till I've found your answer. Apparently the recommandation to use react-router-bootstrap is not bold enough. – Jjang Oct 19 '16 at 23:00
  • @KvothetheBloodless I am new to this can you provide an example or explain "make sure your path is included in React Router" a bit more. – Paschalidis Christos Nov 22 '16 at 19:05
  • @PaschalidisChristos I meant that in my experience, Link Container links only work when you have provided the same link in react-router. https://css-tricks.com/learning-react-router/ – Anant Simran Singh Nov 23 '16 at 09:30
  • But how to link to external site? Seems react-router-bootstrap LinkContainer doesn't work for external site, only for react-router locations. – Eric Hartford Feb 03 '17 at 03:57
  • 8
    This fails to apply the "active" styling to NavItems. – Daniel Arant Feb 08 '17 at 03:26
  • Isn't it recommended way to do imports directly like `import Nav from 'react-bootstrap/lib/Nav'` rather then destructuring whole library?? – Tomasz Mularczyk Feb 08 '17 at 08:40
  • I'm still stuck, can you show your Router definition? please :/ – Emixam23 Jan 18 '18 at 01:42
  • @BrettSun @Gennon, I'm having some trouble to make work this exact same code. I'm getting the error: `TypeError: router.createHref is not a function` inside function `at LinkContainer.render`. Anything that I am missing to do? – manonthemoon Aug 14 '18 at 07:14
  • @manonthemoon It is hard to know exactly what is wrong, but I would recommend you to see if you are using supported versions for each library. Maybe you are using the older LinkContainer with a new version of react-router? There has been several updates to react-router since I wrote this in 2016. :) – Gennon Aug 15 '18 at 09:12
  • Does anyone know how to prevent the home link (e.g. to='/') from being constantly highlighted by default? I'm seeing this in the appearance for the mobile "xs" media query size. EDIT - nvm: exact={true} – Dave Cole Sep 11 '18 at 19:24
  • 1
    I added an answer below that solves the problem with active/activeKey not working. Works with react-bootstrap v_1.0 beta too! (To use with normal version, just sub out Nav.Item fro NavItem, and so on and so forth) – Young Scooter Nov 14 '18 at 23:07
  • This answer is out of date. It is no longer the best answer. For react-router-dom v4 or v5, see Alexey's answer. Use `as={NavLink}`. – Geoffrey Hale Jan 11 '21 at 04:06
73

2020 upd: tested with react-boostrap: 1.0.0-beta.16 and react-router-dom: 5.1.2

2019 upd: for those who are working with react-bootstrap v4 (using 1.0.0-beta.5 currently) and react-router-dom v4 (4.3.1) just use "as" prop from Nav.Link, here is full example:

import { Link, NavLink } from 'react-router-dom'
import { Navbar, Nav } from 'react-bootstrap'

<Navbar>
  {/* "Link" in brand component since just redirect is needed */}
  <Navbar.Brand as={Link} to='/'>Brand link</Navbar.Brand>
  <Nav>
    {/* "NavLink" here since "active" class styling is needed */}
    <Nav.Link as={NavLink} to='/' exact>Home</Nav.Link>
    <Nav.Link as={NavLink} to='/another'>Another</Nav.Link>
    <Nav.Link as={NavLink} to='/onemore'>One More</Nav.Link>
  </Nav>
</Navbar>

Here is working example: https://codesandbox.io/s/3qm35w97kq

Alexey
  • 1,914
  • 16
  • 13
34

Have you tried using react-bootstrap's componentClass ?

import { Link } from 'react-router';
// ...
<Nav pullRight>
  <NavItem componentClass={Link} href="/" to="/">Home</NavItem>
  <NavItem componentClass={Link} href="/book" to="/book">Book Inv</NavItem>
</Nav>
sonlexqt
  • 6,011
  • 5
  • 42
  • 58
  • 1
    This works well! No styling issues and much simpler than the other answers that require overriding, you could also override with a HoC just to avoid the repetition of the href / to. – Tim Lind Mar 07 '18 at 11:07
  • 1
    This is so clean, I used it right now with "target blank" for an external link and works very well. Thanks – Saulo Gomes Apr 04 '18 at 17:58
  • 2
    This is better,without the need to include another package. – sbk201 Aug 30 '18 at 07:48
  • 2
    Just upgraded to 1.0.0-beta.5. It seems they removed support for componentClass :( – Nate-Bit Int Feb 15 '19 at 05:47
16

You can avoid using LinkContainer from react-router-bootstrap. However, componentClass is going to become as in the next release. So, you can use the following snippet for the last version (v1.0.0-beta):

<Nav>
    <Nav.Link as={Link} to="/home" >
        Home
    </Nav.Link>
    <Nav.Link as={Link} to="/book" >
        Book Inv
    </Nav.Link>
    <NavDropdown title="Authorization" id="basic-nav-dropdown">
        <NavDropdown.Item onClick={props.logout}>
            Logout
        </NavDropdown.Item>
    </NavDropdown>
</Nav>
Alexey Kutalo
  • 241
  • 3
  • 6
7

You should not put anchor inside NavItem. By doing this you will see warning in the console:

Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>. See Header > NavItem > SafeAnchor > a > ... > Link > a.

That's because when NavItem is rendered an anchor (direct child of the NavItem) is already there.

Because of the warning above, react will be forced to treat the two anchor as sibling, which caused the style issue.

Ming
  • 4,110
  • 1
  • 29
  • 33
5

Here is a solution for use with react-router 4:

import * as React from 'react';

import { MenuItem as OriginalMenuItem, NavItem as OriginalNavItem } from 'react-bootstrap';

export const MenuItem = ({ href, ...props }, { router }) => (
  <OriginalMenuItem onClick={e => {e.preventDefault();router.transitionTo(href)}} href={href} {...props}/>
);

MenuItem.contextTypes = {
  router: React.PropTypes.any
};

export const NavItem = ({ href, ...props }, { router }) => (
  <OriginalNavItem onClick={e => {e.preventDefault();router.transitionTo(href)}} href={href} {...props}/>
);

NavItem.contextTypes = {
  router: React.PropTypes.any
};
Sohrab Saran
  • 141
  • 11
voodooattack
  • 1,127
  • 9
  • 16
3

IndexLinkContainer is a better option than LinkContainer if you want the inside NavItem to highlight which one is active based on the current selection. No manual selection handler is needed

import { IndexLinkContainer } from 'react-router-bootstrap';
....

//Inside render
<Nav bsStyle="tabs" >
  <IndexLinkContainer to={`${this.props.match.url}`}>
    <NavItem >Tab 1</NavItem>
  </IndexLinkContainer>
  <IndexLinkContainer to={`${this.props.match.url}/tab-2`}>
    <NavItem >Tab 2</NavItem>
  </IndexLinkContainer>
  <IndexLinkContainer to={`${this.props.match.url}/tab-3`}>
    <NavItem >Tab 3</NavItem>
  </IndexLinkContainer>
</Nav>
Sairam Krish
  • 10,158
  • 3
  • 55
  • 67
  • I am not using tabs but would like the link in my nav bar to be highlighted as active. I tried using IndexLinkContainer and it does not work as you indicated. If I go directly to a route it will highlight the right one but not if I just click the links. – Thomas Le Nov 27 '17 at 00:29
  • btw just curios how did you find ```IndexLinkContainer```? couldn't find it anywhere in the docs tho... – Thiem Nguyen Dec 28 '17 at 18:31
  • @ThomasLe Check your using Component vs PureComponent. I've had a few updated issues fixed by switching to Component – FrozenKiwi Sep 24 '18 at 19:40
2

You can use history, just be sure to create the component with router:

in App.js:

// other imports
import {withRouter} from 'react-router';

const NavigationWithRouter = withRouter(Navigation);

//in render()
    <NavigationWithRouter />

in Navigation.js:

//same code as you used before, just make an onClick event for the NavItems instead of using Link

<Nav pullRight>
  <NavItem eventKey={1} onClick={ e => this.props.history.push("/home") } >
    Home
  </NavItem>
  <NavItem eventKey={2} onClick={ e => this.props.history.push("/book") } >
    Book Inv
  </NavItem>
</Nav>
5ar
  • 2,069
  • 10
  • 27
1

To add functionality with "activeKey" prop in react-bootstrap v_1.0 beta, use this format:

<Nav activeKey={//evenKey you want active}>
    <Nav.Item>
        <LinkContainer to={"/home"} >
            <Nav.Link eventKey={//put key here}>
                {x.title}
            </Nav.Link>
        </LinkContainer>
    </Nav.Item>
    //other tabs go here
</Nav>
Young Scooter
  • 474
  • 5
  • 14
1

For the people using Gatsby. If you are using a NavBar and a NavDropdown and you want to use a Link inside a NavDropdown.Item you will get an error that:

<a> cannot be descendant of <a>

For fixing this error try using as="li" :

 <NavDropdown title="Services" id="basic-nav-dropdown">
    <NavDropdown.Item as="li">
      <Link to="/Services" className="nav-link">
        Services
      </Link>
    </NavDropdown.Item>
  </NavDropDown>
galo hernandez
  • 163
  • 1
  • 3