Open Links in a New Tab on your Gatsby MDX Blog
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';
3
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: https://www.gatsbyjs.org/docs/gatsby-link/
9 return <GatsbyLink to={href}>{children}</GatsbyLink>;
10 }
11
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('#');
15
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 );
27}
The rel
attribute is very important, here are some notes from MDN :
Note: When using
target
, addrel="noreferrer noopener"
to avoid exploitation of thewindow.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 usingrel="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';
4
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 );
16}
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';
5
6export default function BlogPost({ data }) {
7 const { body } = data.mdx;
8
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 );
19}
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.