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;