How do I set Gatsby Link to be an <li> tag instead of an <a> tag?

Viewed 500

I am building a Gatsby site and I have the following HTML structure for the website's menu:

<li className="menu-item current-menu-item">
  <Link to="/">Home</Link>
</li>
<li className="menu-item">
  <Link to="/contact">Contact</Link>
</li>

As you can see, the active class is applied to the <li> tag and not the <a> tag that is generated by <Link>. In Vue, we can do something like this:

<router-link to="/contact" tag="li">
  <a href="javascript:void">Contact</a>
</router-link>

The tag prop tells the router-link element that it should render the element as a list item. This way, the active class is applied to the list item and not to the child <a> tag. How do I achieve the same result with Gatsby Link? I can't seem to find an answer to this anywhere. Thank you.

1 Answers

You don't want to use a li instead of an a tag. You just want the li to show as active when the corresponding a tag is active. Links should be a tags as an HTML standard.

Gatsby uses reach-router for routing, so when working with paths and routing, you can use the globalHistory object to get the current path:

import { globalHistory } from '@reach/router'

Then inside your component, get the pathname of the current path:

const pathname = globalHistory.location.pathname

Now all you do is conditionally set the style of each li, based on the value of pathname:

<li className={`menu-item ${pathname === "/" ? "current-menu-item" : ""} `}>
  <Link to="/">Home</Link>
</li>
<li className={`menu-item ${pathname === "/contact" ? "current-menu-item" : ""} `}>
  <Link to="/contact">Contact</Link>
</li>

It might be easier to have an array of your links:

const navLinks = [
  { label: 'Home', to: '/' },
  { label: 'Contact', to: '/contact' },
  { label: 'About', to: '/about' },
]

And then map over them inside the return statement instead of writing them out individually:

return (
  <ul>
    {navLinks.map(link => (
      <li className={`menu-item ${pathname === link.to ? 'current-menu-item' : ''} `}>
        <Link to={link.to}>{link.label}</Link>
      </li>
    ))}
  </ul>
)
Related