diff --git a/.changeset/afraid-scissors-rhyme.md b/.changeset/afraid-scissors-rhyme.md new file mode 100644 index 0000000000..e9df5c9ad3 --- /dev/null +++ b/.changeset/afraid-scissors-rhyme.md @@ -0,0 +1,5 @@ +--- +"react-router-dom": patch +--- + +Improved absolute url detection in `Link` component (now also supports `mailto:` urls) diff --git a/packages/react-router-dom/__tests__/link-href-test.tsx b/packages/react-router-dom/__tests__/link-href-test.tsx index 92b2e828e9..a37d7a7b7d 100644 --- a/packages/react-router-dom/__tests__/link-href-test.tsx +++ b/packages/react-router-dom/__tests__/link-href-test.tsx @@ -128,6 +128,50 @@ describe(" href", () => { expect(renderer.root.findByType("a").props.href).toEqual("//remix.run"); }); + + test(' is treated as external link', () => { + let renderer: TestRenderer.ReactTestRenderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + + } + /> + + + + ); + }); + + expect(renderer.root.findByType("a").props.href).toEqual( + "mailto:remix@example.com" + ); + }); + + test(' is treated as external link', () => { + let renderer: TestRenderer.ReactTestRenderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + + } + /> + + + + ); + }); + + expect(renderer.root.findByType("a").props.href).toEqual( + "web+remix://somepath" + ); + }); }); describe("in a dynamic route", () => { diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx index 73748ff5c2..a2adb57978 100644 --- a/packages/react-router-dom/index.tsx +++ b/packages/react-router-dom/index.tsx @@ -420,8 +420,7 @@ export const Link = React.forwardRef( ) { // `location` is the unaltered href we will render in the tag for absolute URLs let location = typeof to === "string" ? to : createPath(to); - let isAbsolute = - /^[a-z+]+:\/\//i.test(location) || location.startsWith("//"); + let isAbsolute = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(location); // Location to use in the click handler let navigationLocation = location;