Gatsby: [gatsby-plugin-react-next] <Link>'s activeClassName not respected, when pathPrefix is used

Created on 16 Dec 2017  ·  8Comments  ·  Source: gatsbyjs/gatsby

Description

When using gatsby-plugin-react-next and pathPrefix, activeStyle or activeClassName are not taken into account when page is initial loaded. Only after manual triggering navigation, activeStyle or activeClassName are respected.

Environment

Gatsby version: 1.9.135
Node.js version: 8.7.0
Operating System: macOS 10.13.2

File contents (if changed):

gatsby-config.js:

module.exports = {
  siteMetadata: {
    title: `Gatsby Default Starter`,
  },
  plugins: [
      `gatsby-plugin-react-helmet`,
      `gatsby-plugin-react-next`,
    ],
  pathPrefix: `/my-gatsby-site`,
}

package.json:

{
  "name": "gatsby-starter-default",
  "description": "Gatsby default starter",
  "version": "1.0.0",
  "author": "Kyle Mathews <[email protected]>",
  "dependencies": {
    "gatsby": "^1.9.135",
    "gatsby-link": "^1.6.32",
    "gatsby-plugin-react-helmet": "^1.0.8",
    "gatsby-plugin-react-next": "^1.0.6"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "main": "n/a",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --trailing-comma es5 --no-semi --single-quote --write \"src/**/*.js\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "prettier": "^1.9.2"
  }
}

Actual result

Active Links should be styled bold - also on initial page load and not only after navigation did occur.
Testlink: http://gatsbynext-router.surge.sh/my-gatsby-site/page-2

react16

Expected behavior

Same example as above, but without gatsby-plugin-react-next.
Testlink: http://gatsbynext-router-react15.surge.sh/my-gatsby-site/page-2

react15

Steps to reproduce

  1. Setup new vanilla gatdbyJS project

  2. Add gatsby-plugin-react-next plugin

  3. Make use of activeStyle or activeClassName at the <Link> components, that come with the gatsbyJS boilerplate. Eg page-2.js:

<Link activeStyle={{ fontWeight: 'bold' }} to="/">
  Go back to the homepage
</Link>
<br />
<Link activeStyle={{ fontWeight: 'bold' }} to="/page-2/">
  Go to page 2
</Link>
  1. Add a pathPrefix (see gatsby-config.js above) and build a production version of the project using gatsby build --prefix-paths

  2. See result using eg. gatsby serve and test it by initialting page refreshes and navigation

mv public my-gatsby-site                                                                                                                                                                                    
mkdir public                                                                                                                                                                                               
mv my-gatsby-site public                                                                                                                                                                                    
gatsby serve
stale? question or discussion

Most helpful comment

Link's behaviour has changed when reach/router has replaced react-router. @KyleAMathews
mentioned here that new Link won't get that capability. So I wrote my custom Link wrapper, here it is in case someone else needs:

import React from 'react';
import PropTypes from 'prop-types';
import {
  Link as GatsbyLink,
} from 'gatsby';

export default function Link(props) {
  const {
    exact,
    className,
    activeClassName,
    children,
  } = props;

  return (
    <GatsbyLink
      {...props}
      getProps={({ isCurrent, isPartiallyCurrent }) => ({
        className: [
          className,
          (exact && isCurrent) ? activeClassName : '',
          (!exact && isPartiallyCurrent) ? activeClassName : '',
        ].join(' ').trim(),
      })}
    >
      {children}
    </GatsbyLink>
  );
}

Link.propTypes = {
  exact: PropTypes.bool,
  className: PropTypes.string,
  activeClassName: PropTypes.string,
  children: PropTypes.node.isRequired,
};

Link.defaultProps = {
  exact: false,
  activeClassName: 'active',
  className: '',
};

All 8 comments

I'm not entirely sure what's happening here — could you do some more research? We use React Router under the hood so perhaps there's something under the hood there that's buggy. Or perhaps our SSR environment is misconfigured for prefixed links — which don't seem to get as much attention as other parts of Gatsby.

I'm having a similar issue where the link to the home page (to="/") is active on every page of the site.

Could this be a regex bug that triggers a false positive (since it finds / at the beginning of all links)?

Ah! I just found a solution here.

To avoid multiple active links, just set exact={true} on the Link component.

So, while this creates false positives:

<Link to="/" activeClassName="active">Home</Link>

This does not:

<Link to="/" exact={true} activeClassName="active">Home</Link>

Hope that helps solve your issue as well, @mperkh. (My apologies if this doesn't relate!)

Also encountering this (active links don't get styles on page refresh until client route changes happen). @ooloth's problem is something other than the original issue I believe.

Link's behaviour has changed when reach/router has replaced react-router. @KyleAMathews
mentioned here that new Link won't get that capability. So I wrote my custom Link wrapper, here it is in case someone else needs:

import React from 'react';
import PropTypes from 'prop-types';
import {
  Link as GatsbyLink,
} from 'gatsby';

export default function Link(props) {
  const {
    exact,
    className,
    activeClassName,
    children,
  } = props;

  return (
    <GatsbyLink
      {...props}
      getProps={({ isCurrent, isPartiallyCurrent }) => ({
        className: [
          className,
          (exact && isCurrent) ? activeClassName : '',
          (!exact && isPartiallyCurrent) ? activeClassName : '',
        ].join(' ').trim(),
      })}
    >
      {children}
    </GatsbyLink>
  );
}

Link.propTypes = {
  exact: PropTypes.bool,
  className: PropTypes.string,
  activeClassName: PropTypes.string,
  children: PropTypes.node.isRequired,
};

Link.defaultProps = {
  exact: false,
  activeClassName: 'active',
  className: '',
};

Have you solve this problem yet? I also have this issue and set exact={true} on the Link component seems can't solve this

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub issues, we have to clean some of the old issues as many of them have already been resolved with the latest updates.

Please make sure to update to the latest Gatsby version and check if that solves the issue. Let us know if that works for you by adding a comment 👍

This issue is being closed because there hasn't been any activity for at least 30 days. Feel free to open a new one if you still experience this problem 👍

Was this page helpful?
0 / 5 - 0 ratings

Related issues

magicly picture magicly  ·  3Comments

dustinhorton picture dustinhorton  ·  3Comments

hobochild picture hobochild  ·  3Comments

KyleAMathews picture KyleAMathews  ·  3Comments

brandonmp picture brandonmp  ·  3Comments