Home

Open External next/link Links in a New Tab

Add a component that dynamically swaps between next/link and a native anchor tag, and decides how to write the target attribute, all based on the href property.

I like when links to external pages open in a new tab, while internal pages stay in the same tab. It is especially beneficial to keep internal links using the next/link component, since it enables you to take advantage of the router and speed up subsequent page loads.

The first step is to add a custom link component that controls the rendering of the link. The basic logic would look something like this:

import NextLink from "next/link";
import { ExternalLink } from "path/to/external/link";

export const Link = ({ children, ...props }) => {
if (props.href.toString().startsWith("/")) {
return <NextLink {...props}>{children}</NextLink>;
} else {
return <ExternalLink child={children} href={props.href.toString()} />;
}
};

This logic is at the most basic level. If the href property passed to the next/link component begins with a slash (/), consider it an internal link and pass it on to next/link. Otherwise, render some external link component.

Now let’s add the external link component:

import { cloneElement, isValidElement } from "react";

export const ExternalLink = ({ child, href }) => {
if (!isValidElement(child)) {
throw new Error("Child must be a valid React element");
}
if (child.type !== "a") {
throw new Error("Child must be an <a> element");
}
return cloneElement(child, {
href,
target: "_blank",
rel: "noopener noreferrer",
});
};

This may look a little different to you, as it’s not immediately apparent that it’s rendering JSX code.

First, we do some runtime checking to ensure the child is a single <a> component. After validation, we clone that element, adding the appropriate props (target and rel) in the process.

The beauty of this approach is that you don’t have to change anything with your code other than the import statements.

Wherever you have this in your code:

import Link from "next/link";

Change it to this:

import { Link } from "path/to/link/component";
warning

Notice two things here:

  1. The default import (Link) changed to a named import ({ Link }). While the React community still readily uses default imports, I like named imports for better clarity of what you’re importing. Here’s a take I generally align with.
  2. The path/to/link/component should be switched for wherever you put these components.

That’s it! You should now have a working example of automatically opening external links in a new tab.

Playground

In the example below, I combined the components into a single component. Play around with it to make it work for you.

Next Steps

This was just a simple example and a starting point. Where you go from here is up to you.

But now you have this dynamic feature which is super powerful. You could do something like automatically added an icon to indicate that a link is going to open in a new window.

The possibilities are endless!

Let's Connect

Keep Reading

Overriding Next.js Link and Image Components

Next.js ships with these two incredibly useful utility components. You can further abstract these to clean up your code.

Feb 09, 2023

Run React Effect Hook only Once in Strict Mode

Running React in strict mode with Next.js can lead to useEffect callbacks with zero dependencies to run twice in development. Here’s a way around that.

Jun 25, 2022

Use a Class Map to Set Dynamic Styles

Components often need to use styling based on property combinations. There are a number of ways to solve this, but only one I’ve found to be the cleanest.

Feb 03, 2023