Skip to main content

Gatsby Link

For internal navigation, Gatsby includes a built-in <Link> component as well as a navigate function which is used for programmatic navigation.

Gatsby’s <Link> component enables linking to internal pages as well as a powerful performance feature called preloading. Preloading is used to prefetch resources so that the resources are fetched by the time the user navigates with this component. We use an IntersectionObserver to fetch a low-priority request when the Link is in the viewport and then use an onMouseOver event to trigger a high-priority request when it is likely that a user will navigate to the requested resource.

The component is a wrapper around @reach/router’s Link component that adds useful enhancements specific to Gatsby. All props are passed through to @reach/router’s Link component.

Video hosted on egghead.io.

In any situation where you want to link between pages on the same site, use the Link component instead of an a tag.

import React from "react"
import { Link } from "gatsby"
const Page = () => (
  <div>
    <p>
      Check out my <Link to="/blog">blog</Link>!    </p>
    <p>
      {/* Note that external links still use `a` tags. */}
      Follow me on <a href="https://twitter.com/gatsbyjs">Twitter</a>!
    </p>
  </div>
)

Video hosted on egghead.io.

It’s often a good idea to show which page is currently being viewed by visually changing the link matching the current page.

Link provides two options for adding styles to the active link:

  • activeStyle — a style object that will only be applied when the current item is active
  • activeClassName — a class name that will only be added to the Link when the current item is active

For example, to turn the active link red, either of the following approaches is valid:

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

const SiteNavigation = () => (
  <nav>
    <Link
      to="/"
      {/* This assumes the `active` class is defined in your CSS */}      activeClassName="active"    >
      Home
    </Link>
    <Link
      to="/about/"
      activeStyle={{ color: "red" }}    >
      About
    </Link>
  </nav>
)

Video hosted on egghead.io.

The activeStyle or activeClassName prop are only set on a <Link> component if the current URL matches its to prop exactly. Sometimes, we may want to style a <Link> as active even if it partially matches the current URL. For example:

  • We may want /blog/hello-world to match <Link to="/blog">
  • Or /gatsby-link/#passing-state-through-link-and-navigate to match <Link to="/gatsby-link">

In instances like these, we can use @reach/router’s getProps API to to set active styles like in the following example:

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

const PartialNavLink = () => (
  <Link
    to="/blog/"
    getProps={({ isPartiallyCurrent }) =>      isPartiallyCurrent ? { className: "active" } : null    }  >
    Blog
  </Link>
)

Check out this codesandbox for a working example!

Pass state as props to the linked page

Video hosted on egghead.io.

Sometimes you’ll want to pass data from the source page to the linked page. You can do this by passing a state prop to the Link component or on a call to the navigate function. The linked page will have a location prop containing a nested state object structure containing the passed data.

const PhotoFeedItem = ({ id }) => (
  <div>
    {/* (skip the feed item markup for brevity) */}
    <Link
      to={`/photos/${id}`}
      state={{ fromFeed: true }}    >
      View Photo
    </Link>
  </div>
)

const Photo = ({ location, photoId }) => {  if (location.state.fromFeed) {    return <FromFeedPhoto id={photoId} />
  } else {
    return <Photo id={photoId} />
  }
}

Replace history to change “back” button behavior

Video hosted on egghead.io.

There are a few cases where it might make sense to modify the “back” button’s behavior. For example, if you build a page where you choose something, then see an “are you sure?” page to make sure it’s what you really wanted, and finally see a confirmation page, it may be desirable to skip the “are you sure?” page if the “back” button is clicked.

In those cases, use the replace prop to replace the current URL in history with the target of the Link.

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

const AreYouSureLink = () => (
  <Link
    to="/confirmation/"
    replace  >
    Yes, I’m sure
  </Link>
)

How to use the navigate helper function

Video hosted on egghead.io.

Sometimes you need to navigate to pages programatically, such as during form submissions. In these cases, Link won’t work.

Note: navigate was previously named navigateTo. navigateTo is deprecated in Gatsby v2 and will be removed in the next major release.

Instead, Gatsby exports a navigate helper function that accepts to and options arguments.

Argument Required Description
to yes The page to navigate to (e.g. /blog/).
options.state no An object. Values passed here will be available in locations.state in the target page’s props.
options.replace no A boolean value. If true, replaces the current URL in history.

By default, navigate operates the same way as a clicked Link component.

import React from "react"
import { navigate } from "gatsby"
const Form = () => (
  <form
    onSubmit={event => {
      event.preventDefault()

      // TODO: do something with form values
      navigate("/form-submitted/")    }}
  >
    {/* (skip form inputs for brevity) */}
  </form>
)

Add state to programmatic navigation

To include state information, add an options object and include a state prop with the desired state.

import React from "react"
import { navigate } from "gatsby"

const Form = () => (
  <form
    onSubmit={event => {
      event.preventDefault()

      // Implementation of this function is an exercise for the reader.
      const formValues = getFormValues()

      navigate(
        "/form-submitted/",
        {          state: { formValues },        }      )
    }}
  >
    {/* (skip form inputs for brevity) */}
  </form>
)

Replace history during programmatic navigation

If the navigation should replace history instead of pushing a new entry into the navigation history, add the replace prop with a value of true to the options argument of navigate.

import React from "react"
import { navigate } from "gatsby"

const Form = () => (
  <form
    onSubmit={event => {
      event.preventDefault()

      // TODO: do something with form values
      navigate(
        "/form-submitted/",
        { replace: true }      )
    }}
  >
    {/* (skip form inputs for brevity) */}
  </form>
)

Add the path prefix to paths using withPrefix

It is common to host sites in a sub-directory of a site. Gatsby lets you set the path prefix for your site. After doing so, Gatsby’s <Link> component will automatically handle constructing the correct URL in development and production.

For pathnames you construct manually, there’s a helper function, withPrefix that prepends your path prefix in production (but doesn’t during development where paths don’t need prefixed).

import { withPrefix } from "gatsby"

const IndexLayout = ({ children, location }) => {
  const isHomepage = location.pathname === withPrefix("/")

  return (
    <div>
      <h1>Welcome {isHomepage ? "home" : "aboard"}!</h1>
      {children}
    </div>
  )
}

This component is intended only for links to pages handled by Gatsby. For links to pages on other domains or pages on the same domain not handled by the current Gatsby site, use the normal <a> element.

Sometimes you won’t know ahead of time whether a link will be internal or not, such as when the data is coming from a CMS. In these cases you may find it useful to make a component which inspects the link and renders either with Gatsby’s <Link> or with a regular <a> tag accordingly.

Since deciding whether a link is internal or not depends on the site in question, you may need to customize the heuristic to your environment, but the following may be a good starting point:

import { Link as GatsbyLink } from "gatsby"

// Since DOM elements <a> cannot receive activeClassName,
// destructure the prop here and pass it only to GatsbyLink
const Link = ({ children, to, activeClassName, ...other }) => {
  // Tailor the following test to your environment.
  // This example assumes that any internal link (intended for Gatsby)
  // will start with exactly one slash, and that anything else is external.
  const internal = /^\/(?!\/)/.test(to)

  // Use Gatsby Link for internal links, and <a> for others
  if (internal) {
    return (
      <GatsbyLink to={to} activeClassName={activeClassName} {...other}>
        {children}
      </GatsbyLink>
    )
  }
  return (
    <a href={to} {...other}>
      {children}
    </a>
  )
}

export default Link

File Downloads

You can similarly check for file downloads:

  const file = /\.[0-9a-z]+$/i.test(to)

  ...

  if (internal) {
    if (file) {
        return (
          <a href={to} {...other}>
            {children}
          </a>
      )
    }
    return (
      <GatsbyLink to={to} {...other}>
        {children}
      </GatsbyLink>
    )
  }

edit this page on GitHub