2

Converting a site from HTML to Gatsby I have a basic Bootstrap 4 navigation:

<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
    <div class="container">
        <a class="navbar-brand logo" href="/">
            <!-- SVG Logo -->
        </a>
        <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
            Menu
            <i class="fas fa-bars"></i>
        </button>
        <div class="collapse navbar-collapse" id="navbarResponsive">
            <ul class="navbar-nav ml-auto">
                <li class="nav-item">
                    <a href="#" class="nav-link">Home</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

In gatsby-config.js I have defined my menu and I can query and pass down from index.js to my Navigation.js component. Per memory the navbar is built as a list when I referenced the Navbar docs. When I research the documentation for React Bootstrap and other examples everything is built as a href inside a div and there are multiple ways it's written, examples:

reference Q&A: React-Bootstrap link item in a navitem

code:

<Nav.Link as={Link} eventKey={l.link}>
  {l.name}
</Nav.Link>

renders:

<a aria-current="page" class href=""><li data-rb-event-key="/" class="nav-link">home</li></a>
<a href="/mon"><li data-rb-event-key="mon" class="nav-link">Monday</li></a>
<a href="/tues"><li data-rb-event-key="tues" class="nav-link">Tuesday</li></a>

reference repo: Gatsby React Bootstrap Start

code:

<Link key={k} to={l.link}>
  <Nav.Link as="li" eventKey={l.link}>
    {l.name}
  </Nav.Link>
</Link>

renders:

<div class="justify-content-end navbar-nav">
  <a aria-current="page" class="" href="/">
    <li data-rb-event-key="/" class="nav-link">home</li>
  </a>
  <a href="/mon">
    <li data-rb-event-key="mon" class="nav-link">Monday</li>
  </a>
  <a href="/tues">
    <li data-rb-event-key="tues" class="nav-link">Tuesday</li>
  </a>
</div>

Full component for reference:

Navigation.js:

import React from 'react'
import { Link } from 'gatsby'

// Components
import Logo from './Logo'

// Bootstrap
import { Navbar, Container, Nav } from 'react-bootstrap'

// React Icons
import { GoThreeBars } from 'react-icons/go'

const Navigation = ({ menuLinks }) => {
  return (
    <Navbar id="headNav" collapseOnSelect expand="lg">
      <Container>
        <Navbar.Brand href="/">
          <Logo id="logo" />
        </Navbar.Brand>
        <Navbar.Toggle
          className="navbar-toggler navbar-toggler-right"
          aria-controls="responsive-navbar-nav"
        >
          Menu <GoThreeBars />
        </Navbar.Toggle>
        <Navbar.Collapse id="responsive-navbar-nav" className="collapse navbar-collapse">
          <Nav className="justify-content-end">
            {menuLinks.map((l, k) => (
              <Link key={k} to={l.link}>
                <Nav.Link as="li" eventKey={l.link}>
                  {l.name}
                </Nav.Link>
              </Link>
            ))}
          </Nav>
        </Navbar.Collapse>
      </Container>
    </Navbar>
  )
}

export default Navigation

In React Bootstrap what is the proper way to write links so that it will replicate the Bootstrap 4 documentation and the sample above? Do I need to use Link from Gastby and Nav.Link from React Bootstrap together?

DᴀʀᴛʜVᴀᴅᴇʀ
  • 7,681
  • 17
  • 73
  • 127

1 Answers1

0

Gatsby's <Link> extends from @reach/router (by React) and adds some additional features to the "traditional" React's behavior.

Creating a structure like the following:

<Link key={k} to={l.link}>
  <Nav.Link eventKey={l.link}>
    {l.name}
  </Nav.Link>
</Link>

Note: I've removed the as prop, by default it will take an anchor.

You are rendering an <a> as a descendant of another <a>, which will lead to some caveats and some potential issues. So you should avoid it.

If you are using React's Bootstrap, the <Link> component is inherited from React instead of Gatsby, which is also good and it will keep the main features of the component (rehydrate only the needed parts, keep the navigation across the application, etc).

The ideal approach combining as well as Bootstrap plus Gatsby should and the structure you've provided will be something like this:

  <ul>
    <Nav.Link as="li" eventKey={l.link}>
      <Link key={k} to={l.link}>
        {l.name}
      </Link>
    </Nav.Link>
  </ul>

<Nav> is inherited from Bootstrap while <Link> from Gatsby, in this scenario, you'll render a list (<ul> and set of <li>s) with an <a> as a descendant, which makes complete sense.

The code that you've provided:

  <Link key={k} to={l.link}>
    <Nav.Link as="li" eventKey={l.link}>
      {l.name}
    </Nav.Link>
  </Link>

It's also valid, but it's rendering a <li> as a descendant of an <a> without being wrapped in a list (<ul>), in addition, would be a one-item list so it's not semantic.

You can also use the provided starter approach, which doesn't use a list:

  <Nav className="mr-auto" activeKey={pageInfo && pageInfo.pageName}>
    <Link to="/page-2" className="link-no-style">
      <Nav.Link as="span" eventKey="page-2">
        Page 2
      </Nav.Link>
    </Link>
  </Nav>

And it's perfectly valid and semantic.

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67