How to use named anchors with the Shadow DOM

Named Anchors

Using named anchors to navigate to specific sections of a page is a simple concept, but it can become more complicated when dealing with the shadow DOM. Fortunately, this article presents a solution to this problem.

In typical usage, named anchors are employed to navigate to specific sections of a page. However, this technique must be adjusted when the sections the user wants to navigate to are located in a shadow DOM.

To demonstrate this, the article provides an example of a list of named anchors in the main document, with multiple targets inside the shadow DOM of a custom element. When a user clicks on one of the named anchors (represented by the A tag), they will be smoothly scrolled to the corresponding paragraph tag inside the custom element “my-component”.

Named Anchors
<body>
...
<ul>
    <li><a href="#anchor1">Anchor 1</a></li>
    <li><a href="#anchor2">Anchor 2</a></li>
</ul>
 
<my-component>
  <!-- shadow dom -->
      <p id="anchor1"> ... Some Text for Anchor 1 ...</p>
      <p id="anchor2"> ... Some Text for Anchor 2 ...</p>
  <!-- shadow dom -->
</my-component>

...
</body>

On line 10 and 11 we have added 2 anchors on the paragraphs we want to navigate to ( id=”anchor1″ and id=”anchor2″). Note: In this scenario, both of these paragraphs are hidden from the main document by a Shadow DOM.

When the user clicks on Anchor 1 (line 4) they will be scrolled to the paragraph with the corresponding anchor. To accomplish this we use the following code:

//Wait for the component to be loaded
window.customElements.whenDefined('my-component').then(() => {
    const componentDocument = document.querySelector("my-component").shadowRoot;

    document.addEventListener("click", (e) => {
        const target = e.target;
        if (target.matches('a[href^="#"]')) {
            e.preventDefault();
            componentDocument.querySelector(target.getAttribute('href')).scrollIntoView({
                behavior: 'smooth'
            });
        }
    });
});

On line 3, we get the shadow root of the custom element, which is essentially it’s own document tree. We then use this to find the anchor to navigate to on line 9.