Skip to content

Instantly share code, notes, and snippets.

Created Jan 20, 2017
What would you like to do?
Replace internal links with history.pushState based navigation but leave external links unmodified
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<a href="/app.html">app.html</a>
These should use the instantaneous single page app navigation:
<li><a href="/page/1">App Page 1</a></li>
<li><a href="/page/2">App Page 2</a></li>
<li><a href="/page/3">App Page 3</a></li>
<li><a href="/page/3#downabit">Page 3 with anchor</a> (doesn't quite work as intended)</li>
These should use normal link navigation:
<li><a href="#downabit">Relative anchor</a></li>
<li><a href="/page/3" target="_blank">App Page 3 (new tab)</a></li>
<li><a href="">External link</a></li>
<div id="downabit">Here is this bit</div>
(function () {
window.HijackLinks = hijackLinks
function hijackLinks () {
for (let node of document.getElementsByTagName('a')) {
console.log(node, node.nodeName, node.href)
node.addEventListener('click', singlePageAppNavigate, false)
function singlePageAppNavigate (e) {
if (isLocalHref( {
let node =
history.pushState({}, '', node.href)
// Firefox on my phone does not show the new URL in the URL bar. :-(
// But if I tap the address bar to edit it it does.
function emitNavigateEvent () {
let event = new Event('navigate')
window.addEventListener('popstate', function (e) {
// I'd like to acknowledge Alexandre Dieulot (
// @link
function isLocalHref (a) {
if ( !==
|| a.protocol !== window.location.protocol
|| a.hasAttribute('download')
// This one is subtle. This (re)enables the hash to be used for it's original in-page navigation behavior.
|| (a.pathname === window.location.pathname && ===
) {
return false
return true
// User code
window.addEventListener('navigate', function(){
// Bizarrely enough, doing this "fixes" the URL bar in Firefox on my phone.
// But not if I do it in singlePageAppNavigate().
document.title = window.location.pathname
Copy link

wmhilton commented Jan 20, 2017

An experiment, heavily inspired by

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