'Svelte reactive statement with a variable fron onMount

I'm trying to style the currently active tab of my web project with the class "active". To target my tab elements I am using

    onMount(() => {
    const links = document.querySelectorAll(".topnav a");
});

I am then using a reactive statement to style the appropriate element like this

    $: {
    links.forEach((link) => {
        if (link.getAttribute("id") === $page.url.pathname) {
            link.classList.add("active");
        } else {
            link.classList.remove("active");
        }
    });
}

However, I have no way of sharing the links variable to my reactive statement. I also tried putting document.querySelectorAll inside my reactive statement (not using onMount at all), which worked flawlessly until i reloaded the page. What is the conventional approach to this?



Solution 1:[1]

You need to declare the variable outside of onMount so it is in scope of the reactive statement. E.g.

let links = null;

onMount(() => {
    links = ...;
);

$: if (links != null) {
    links.forEach((link) => {
});

Solution 2:[2]

Using document.querySelectorAll is not idiomatic Svelte.

Changing class (or other attributes) use the template syntax:

<a class:active={link.id === $page.url.pathname}>
  {link.label}
</a>

If you really need access to the DOM api's Svelte has bind:this or action to get access to specific elements.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 H.B.
Solution 2 Bob Fanger