Skip to content

fix: HashHistory Link hrefs escape the hash router - #9

Open
jligeza wants to merge 1 commit into
strblr:masterfrom
jligeza:fix/hashhistory-link-href
Open

fix: HashHistory Link hrefs escape the hash router#9
jligeza wants to merge 1 commit into
strblr:masterfrom
jligeza:fix/hashhistory-link-href

Conversation

@jligeza

@jligeza jligeza commented Jun 14, 2026

Copy link
Copy Markdown

Problem

With HashHistory, <Link> renders an anchor whose href is the plain route-space path (e.g. /posts/123) instead of the hash form (#/posts/123).

Plain left-clicks still work because Link's onClick intercepts them and routes through router.navigate, which goes through HashHistory.push (the only place that prepends #). But native browser link actions — Ctrl/Cmd-click, middle-click, "copy link address", "open in new tab" — use the href directly and bypass the click handler. On a static host (e.g. GitHub/GitLab Pages) the browser then requests /posts/123 from the server, which doesn't exist, so the link is broken.

The root cause is that the mapping from an internal URL to a real browser URL lives only inside each history's push. Link has no read-only way to ask the history "what href should this URL render as", so it falls back to the raw path.

Fix

Add an optional createHref(url) to HistoryLike:

  • BrowserHistory / MemoryHistory: identity (url => url)
  • HashHistory`: `url => `#${url}`

Link now sets href: router.history.createHref?.(url) ?? url.

  • Navigation is unchanged — navigate still pushes the plain url, and HashHistory.push still adds the single #, so there is no double-#.
  • createHref is optional on the interface, so existing custom HistoryLike implementations keep working (they fall back to identity).
  • BrowserHistory/MemoryHistory hrefs are byte-for-byte unchanged.

Verification

Rendering a real <Link to="/posts/123"> through a real HashHistory router with react-dom/server:

Before: <a href="/posts/123">
After: <a href="#/posts/123">

BrowserHistory.createHref('/posts/123')/posts/123 (unchanged), HashHistory.createHref('/posts/123')#/posts/123.

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.

1 participant