Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow Link's "to" prop to accept external urls #9900

Merged
merged 10 commits into from
Jan 18, 2023
39 changes: 39 additions & 0 deletions packages/react-router-dom/__tests__/link-href-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,45 @@ describe("<Link> href", () => {
["/about", "/about"]
);
});

test('<Link to="https://remix.run"> is treated as external link', () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter initialEntries={["/inbox/messages"]}>
<Routes>
<Route path="inbox">
<Route
path="messages"
element={<Link to="https://remix.run" />}
/>
</Route>
</Routes>
</MemoryRouter>
);
});

expect(renderer.root.findByType("a").props.href).toEqual(
"https://remix.run"
);
});

test('<Link to="//remix.run"> is treated as external link', () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter initialEntries={["/inbox/messages"]}>
<Routes>
<Route path="inbox">
<Route path="messages" element={<Link to="//remix.run" />} />
</Route>
</Routes>
</MemoryRouter>
);
});

expect(renderer.root.findByType("a").props.href).toEqual("//remix.run");
});
});

describe("in a dynamic route", () => {
Expand Down
8 changes: 5 additions & 3 deletions packages/react-router-dom/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,9 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
},
ref
) {
let href = useHref(to, { relative });
let toString = typeof to === "string" ? to : createPath(to);
let isExternal = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(toString);
let href = useHref(toString, { relative });
let internalOnClick = useLinkClickHandler(to, {
replace,
state,
Expand All @@ -430,8 +432,8 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
// eslint-disable-next-line jsx-a11y/anchor-has-content
<a
{...rest}
href={href}
onClick={reloadDocument ? onClick : handleClick}
href={isExternal ? toString : href}
onClick={isExternal || reloadDocument ? onClick : handleClick}
mcansh marked this conversation as resolved.
Show resolved Hide resolved
ref={ref}
target={target}
/>
Expand Down