Go Back

Building a backlink web component

Why?

I recently got the requirement to create a link that basically acts like the browser back button. And I, being interested in deepening my understanding of web components, thought about extending the native HTMLAnchorElement. Web Components offer a native way of extending built-in components using the is attribute which was perfect for the job.

There were two additional problems to consider:

  • It should show its target when hovered.
  • It should not lead to an infinite back loop.

Solving the first requirement is pretty easy. We just set its href-attribute to document.referrer. This has the additional advantage over using an actual button that middle-clicking works natively.

The second requirement is a little trickier. If you navigated through the site from Page A to Page B to Page C and you'd press the back button on Page C, you expect to go to Page B. If you now press the back button on Page B you expect to go to Page A. However, links put themselves on the history stack of the browser. If we were to use the default action of the anchor element for the back button on Page C, one would actually go from Page B back to Page C. Disaster!

To avoid this, I used the back-function of the History-API and preventDefault to prevent the default browser behavior.

Additionally, we don't want to navigate internally. If, for example, we provide some footnotes which use fragment-identifiers to jump to the footnote, we don't want our back button to re-navigate to those. For this purpose we count all fragment navigations and go back by that amount + 1.

Implementation

The implementation is pretty simple.

class ExBacklink extends HTMLAnchorElement {

    goBackCount = 1;
    constructor(){
        super();
    }

    connectedCallback() {
        window.addEventListener('popstate', () => {
            //we store how often we navigate internally, in order to go back to the right page
            //i.e. we want to ignore page#id-1 
            this.goBackCount++;
        });
        this.href = document.referrer;
        this.addEventListener('click', (event) => {
            //we simulate the browser back button, meaning that
            // - we go back to the previous page 
            // - we don't put the current page back on the history stack
            //Meaning that if the user went page A -> B -> C
            //And presses this link on page "C" he goes back to B
            //And if he uses the browser back function on "B" he goes to "A"
            //If we would put it on the stack he would go from "B" back to "C"
            history.go(-this.goBackCount);
            event.preventDefault();
        })
    }
}

customElements.define("ex-back-link", ExBacklink, {extends: "a"});

Note that the component class extends HTMLAnchorElement and that we also define the extension in the customElement.define call.

Using the is-Attribute we can now use any given link as a backlink. I added some a11y support here.

<div class="back-wrap">
    <a is="ex-back-link" title="Go Back"><span class="sr-only">Go Back</span></a>
</div>

Conclusion

Extending native HTML elements is an interesting solution to several problems regarding web components, including that it is not easy to access the content of web components without also using a shadow dom.
This was a rather simple use case for it, but I can imagine using it in more complex native projects in the future.