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';34export default function Link({ children, href }) {5 if (href.startsWith('/')) {6 // Use Gatsby's Link component for internal site navigation7 // to benefit from the preloading features8 // See: https://www.gatsbyjs.org/docs/gatsby-link/9 return <GatsbyLink to={href}>{children}</GatsbyLink>;10 }1112 // Check if the link is for a section on the page13 // We don't want to add the attributes for the on page links14 const onPage = href.startsWith('#');1516 return (17 <a18 href={href}19 // Open the link in a new page20 target={onPage ? null : '_blank'}21 // Add noopener and noreferrer for security reasons22 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';45export default function Layout({ children }) {6 return (7 <MDXProvider8 components={{9 // Map the HTML elements to React components10 a: Link11 }}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';56export default function BlogPost({ data }) {7 const { body } = data.mdx;89 return (10 <MDXProvider11 components={{12 // Map the HTML elements to React components13 a: Link14 }}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.