@@ -50,15 +50,17 @@ export const Link = React.forwardRef(function Link(
50
50
51
51
// When the page is embedded in an iframe, for security reasons other urls cannot be opened.
52
52
// In this case, we open the link in a new tab.
53
- if ( isExternal && window . self !== window . top ) {
53
+ if ( window . self !== window . top && isExternalLink ( href , window . location . origin ) ) {
54
54
event . preventDefault ( ) ;
55
55
window . open ( href , '_blank' ) ;
56
56
}
57
57
58
58
domProps . onClick ?.( event ) ;
59
59
} ;
60
60
61
- if ( isExternal ) {
61
+ // We test if the link is external, without comparing to the origin
62
+ // as this will be rendered on the server and it could result in a mismatch.
63
+ if ( isExternalLink ( href ) ) {
62
64
return (
63
65
< a ref = { ref } { ...domProps } href = { href } onClick = { onClick } >
64
66
{ children }
@@ -72,3 +74,27 @@ export const Link = React.forwardRef(function Link(
72
74
</ NextLink >
73
75
) ;
74
76
} ) ;
77
+
78
+ /**
79
+ * Check if a link is external, compared to an origin.
80
+ */
81
+ function isExternalLink ( href : string , origin : string | null = null ) {
82
+ if ( ! URL . canParse ) {
83
+ // If URL.canParse is not available, we quickly check if it looks like a URL
84
+ return href . startsWith ( 'http' ) ;
85
+ }
86
+
87
+ if ( ! URL . canParse ( href ) ) {
88
+ // If we can't parse the href, we consider it a relative path
89
+ return false ;
90
+ }
91
+
92
+ if ( ! origin ) {
93
+ // If origin is not provided, we consider the link external
94
+ return true ;
95
+ }
96
+
97
+ // If the url points to the same origin, we consider it internal
98
+ const parsed = new URL ( href ) ;
99
+ return parsed . origin !== origin ;
100
+ }
0 commit comments