How to prevent History’s back button from leaving your app’s domain

Mafalda.Lome
2 min readJul 15, 2021

Problem: your web application history’s goBack function navigates away from your domain. For example, if you came to your application from a different domain, say www.google.com and used your app’s back button, it sends you back to google instead of forcing the user to stay within your app.

Solution: The Proxy design pattern!

By now you’ve probably discovered that History’s length attribute is utterly useless. It fails to reset to 0 when you navigate away from your application and then return again. So if you’ve visited 5 paths in your app, went to google to check on something, then came back to your app and clicked around some more, history would continue recording from 5. WTF!

So if you’re in a situation where you need to regulate History’s stack length but cannot trust the built-in length attribute, a simple solution is building a Proxy that intercepts history’s implementations and tracks the stack length itself!

Here’s an example:

export class LocalHistory implements History {  private readonly browserHistory = createBrowserHistory();  private localLength: number = 0;  public get action(): Action {
return this.browserHistory.action
}
public get location(): Location {
return this.browserHistory.location;
}
public readonly createHref = (...args: Parameters<History["createHref"]>) => {
return this.browserHistory.createHref(...args);
}
public readonly push = (...args: Parameters<History["push"]>) => {
this.localLength++;
return this.browserHistory.push(...args);
}
public readonly replace = (...args: Parameters<History["replace"]>) =>
{
return this.browserHistory.replace(...args);
};
public readonly go = (delta: number) => {
this.localLength += delta;
return this.browserHistory.go(delta);
};
public readonly goBack = () => {
if (this.localLength > 0) {
this.localLength--;
return this.browserHistory.goBack();
} else {
this.push("/");
}
};
public readonly goForward = () => {
this.localLength++;
return this.browserHistory.goForward();
};
public readonly listen = (...args: Parameters<History["listen"]>) =>
{
return this.browserHistory.listen(...args);
};
public get length() {
return this.browserHistory.length;
};
}

As you can see, we’re tracking our own attribute localLength that gets incremented with push actions and decremented with pop actions. The LocalHistory class simply calls the normal browser history’s functions so you don’t have to re-invent the wheel, just add you own layer of logic!

--

--