Skip to content

feat(link): accept external URLs in Link to prop (#4901)#7678

Draft
sanjibani wants to merge 1 commit into
TanStack:mainfrom
sanjibani:fix/link-external-url-types
Draft

feat(link): accept external URLs in Link to prop (#4901)#7678
sanjibani wants to merge 1 commit into
TanStack:mainfrom
sanjibani:fix/link-external-url-types

Conversation

@sanjibani

@sanjibani sanjibani commented Jun 23, 2026

Copy link
Copy Markdown

Summary

useLinkProps already detects absolute URLs in the to prop at runtime — see packages/react-router/src/link.tsx:113-154: it parses to with new URL() and renders it as an anchor's href when it looks external, still applying isDangerousProtocol filtering.

But the type-level constraint from ToPathOption rejects any string with a scheme, so users get a TypeScript error for valid runtime usage:

<Link to="https://example.com" />        // TS error today
<Link to="mailto:user@example.com" />    // TS error today
<Link to="tel:+15551234567" />           // TS error today

This PR widens ToPathOption to also accept the four protocols in the default protocol allowlist (http:, https:, mailto:, tel:). Internal route paths (/dashboard, ../profile) continue to type-check unchanged — the union only widens what is accepted.

It also exposes the new ExternalUrl template-literal type from router-core so apps that want to type their own Link-like components can reuse it.

Test plan

Added packages/router-core/tests/external-url.test-d.ts with 7 type assertions covering:

  • https://, http://, mailto:, tel: URL patterns matching ExternalUrl
  • Internal route paths correctly NOT matching ExternalUrl
  • ToPathOption accepting all four external URL protocols
  • ToPathOption still accepting internal route paths (backward compat)

Verified locally with vitest --typecheck: 7/7 pass, no new type errors.

Fixes #4901

The runtime `useLinkProps` already detects absolute URLs in the `to`
prop (it parses `to` with `new URL()` and renders it as an anchor's
`href` when it looks external), but the type-level constraint from
`ToPathOption` rejected any string with a scheme — so users got a
TypeScript error for valid runtime usage:

    <Link to="https://example.com" />  // TS error
    <Link to="mailto:user@example.com" />  // TS error
    <Link to="tel:+15551234567" />  // TS error

Widen `ToPathOption` to also accept the four protocols in the default
protocol allowlist (http:, https:, mailto:, tel:). Internal route paths
(`/dashboard`, `../profile`) continue to type-check unchanged — the
union only widens what is accepted.

Expose the new `ExternalUrl` template-literal type from router-core so
apps that want to type their own Link-like components can reuse it.

Fixes TanStack#4901
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 04a7677a-7ceb-47d9-a374-5273fff49d30

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sanjibani

Copy link
Copy Markdown
Author

Note: this PR was opened in draft state because the OAuth token used by my tooling does not have the GraphQL markPullRequestReadyForReview scope for cross-fork PRs on TanStack/router (same token-rotation side effect that affects BerriAI/litellm). Please mark ready-for-review when you start reviewing.

The change itself is straightforward: widen ToPathOption (router-core/src/link.ts) to union with a new ExternalUrl template-literal type matching the four default allowlist protocols. Runtime handling already exists in useLinkProps — this just makes the types match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Link should accept external links

1 participant