React-Bootstrap link item in a navitem

React RouterReact Bootstrap

React Router Problem Overview


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.

React Router Solutions


Solution 1 - React Router

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.

Solution 2 - React Router

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

Solution 3 - React Router

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>

Solution 4 - React Router

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>

Solution 5 - React Router

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.

Solution 6 - React Router

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
};

Solution 7 - React Router

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>

Solution 8 - React Router

You can use [history][1], just be sure to create the component [with router][2]:

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>

[1]: https://reacttraining.com/react-router/web/api/history "history object" [2]: https://reacttraining.com/react-router/web/api/withRouter "withRouter()"

Solution 9 - React Router

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>

Solution 10 - React Router

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>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionchad schmidtView Question on Stackoverflow
Solution 1 - React RouterGennonView Answer on Stackoverflow
Solution 2 - React RouterAlexeyView Answer on Stackoverflow
Solution 3 - React RoutersonlexqtView Answer on Stackoverflow
Solution 4 - React RouterAlexey KutaloView Answer on Stackoverflow
Solution 5 - React RouterMingView Answer on Stackoverflow
Solution 6 - React RoutervoodooattackView Answer on Stackoverflow
Solution 7 - React RouterSairam KrishView Answer on Stackoverflow
Solution 8 - React Router5arView Answer on Stackoverflow
Solution 9 - React RouterYoung ScooterView Answer on Stackoverflow
Solution 10 - React Routergalo hernandezView Answer on Stackoverflow