Web development and Linux system administration.

If you prefer to open all the external links on your Gatsby MDX powered blog in a new tab, here's how to do it without installing any plugins.

1. Create a component to replace the a element

When using MDX you can replace the default HTML elements that Markdown compiles to with your own components, so we can replace the a element with our own custom Link component.

Here's an example component that wraps Gatsby's Link component and uses it only for internal links, and adds target="_blank" for the external links:

1import React from 'react';
2import { Link as GatsbyLink } from 'gatsby';
4export default function Link({ children, href }) {
5 if (href.startsWith('/')) {
6 // Use Gatsby's Link component for internal site navigation
7 // to benefit from the preloading features
8 // See:
9 return <GatsbyLink to={href}>{children}</GatsbyLink>;
10 }
12 // Check if the link is for a section on the page
13 // We don't want to add the attributes for the on page links
14 const onPage = href.startsWith('#');
16 return (
17 <a
18 href={href}
19 // Open the link in a new page
20 target={onPage ? null : '_blank'}
21 // Add noopener and noreferrer for security reasons
22 rel={onPage ? null : 'noopener noreferrer'}
23 >
24 {children}
25 </a>
26 );

The rel attribute is very important, here are some notes from MDN:

Note: When using target, add rel="noreferrer noopener" to avoid exploitation of the window.opener API;

Note: Linking to another page with target="_blank" will run the new page in the same process as your page. If the new page executes JavaScript, your page's performance may suffer. This can also be avoided by using rel="noreferrer noopener".

SEO Note:

If you want the same result as the gatsby-remark-external-links plugin, you need to also add nofollow.

Usually, you want to do this if you don't have control over the posted content (eg: user-generated content), but if you're adding this to your blog, you can safely ignore it because you won't link to sites that you don't endorse in the first place and if you link to sites usually you want them to benefit from this link.

2. Replace the a elements with the new component

Now you can replace the a elements in your MDX files with this new Link component which can be done using MDXProvider (uses the React's Context API), the idea is to wrap the MDXRenderer component.

You can do this in your Layout component:

1import React from 'react';
2import { MDXProvider } from '@mdx-js/react';
3import Link from './Link';
5export default function Layout({ children }) {
6 return (
7 <MDXProvider
8 components={{
9 // Map the HTML elements to React components
10 a: Link
11 }}
12 >
13 {children}
14 </MDXProvider>
15 );

Or directly where you're using the MDXRenderer component:

1import React from 'react';
2import { MDXRenderer } from 'gatsby-plugin-mdx';
3import { MDXProvider } from '@mdx-js/react';
4import Link from './Link';
6export default function BlogPost({ data }) {
7 const { body } = data.mdx;
9 return (
10 <MDXProvider
11 components={{
12 // Map the HTML elements to React components
13 a: Link
14 }}
15 >
16 <MDXRenderer>{body}</MDXRenderer>
17 </MDXProvider>
18 );

That's it, now all the links in your MDX files will be using this new Link component and the external links will open in a new tab.

© 2020 All rights reserved

Made with Gatsby and hosted on Netlify