sprucegoose
sprucegoose

Reputation: 610

anchor link in Svelte app using page.js routing

I have an anchor tag on a page in my Svelte app. The link to the anchor works on the page itself, but I can't link to the anchor from another page. And when I enter the URL with the anchor, the page doesn't scroll down. I need to be able to give people a link and have them go to a specific part of the page.

Here's the relevant code:

    <script>
      function scrollIntoView({ target }) {
        const el = document.querySelector(target.getAttribute("href"));
        if (!el) return;
        el.scrollIntoView({
          behavior: "smooth",
        });
      }
    </script>

    <nav>
      <a href="#here" on:click|preventDefault={scrollIntoView}>go to anchor</a>
    </nav>

    <main>
      <section id="section-1">
        ... lots of lorem ipsum ...
      </section>
      <section>
        <h2 id="here">anchor</h2>

And I have a REPL here: https://svelte.dev/repl/e651218bdb47455d9cafe8bff27c8d7b?version=3.24.0

I'm using page.js for my routing to components -- I haven't found anything specific about targeting anchor tags in the documentation.

Any help would be greatly appreciated.

Upvotes: 4

Views: 2229

Answers (2)

periwinkle
periwinkle

Reputation: 1

It looks like the only other answer solved the original problem. This is my first post here, so forgive me if this is poor etiquette, but I wound up here by having the same general problem (cross-page anchor links not scrolling to their id'ed elements) but by different mechanics, so I'm posting this for the next person who winds up reading this thread in case the cause of their problem matches mine.

Using CSS to set my scrolling behavior, and using just the element's href attribute to set cross-page anchor links, I was having the problem that I would click the cross-page anchor link and, upon arrival on the target page, the window would scroll a few pixels and then hang up.

I tried a variety of Svelte and JS workarounds and, although logging key variables to the console showed that the related data was changing as intended, the broken behavior persisted.

In my case, the problem turned out to be that, on the target page for the cross-page anchor links, I was tracking the vertical scroll with...

svelte:window(bind:scrollY)

That's Pug syntax, but you get the point.

Getting rid of that special element (and, of course, all related code) un-broke the cross-page anchor links. Bringing it back broke them again. So far, over a period of days, I've re-tested this observation and it's one-to-one.

I don't understand the deeper mechanics, but I'm fairly confident that this vertical scroll binding to the svelte:window element is the isolated x-factor because I found a workaround with vanilla JS to accomplish what I was doing with the binding, and the cross-page anchor links still work with the workaround in place.

Upvotes: 0

brunnerh
brunnerh

Reputation: 184296

You don't need JS for smooth scrolling, just add some CSS:

/* :global if in component */
:global(html) {
    scroll-behavior: smooth;
}

REPL

As for scroll on page load, that is an issue of client-side rendering. For SSR the CSS alone takes care of everything but if the element that should be scrolled to is added after the page is loaded, the scroll will not happen.

One way of dealing with that would be to add an onMount, ideally high up in the component hierarchy so it triggers after everything is mounted, which manually performs the scroll:

onMount(() => {
  const { hash } = document.location;
  const scrollTo = hash && document.getElementById(hash.slice(1));
  if (scrollTo)
    scrollTo.scrollIntoView();
});

(Some of that logic is from SvelteKit which does all that automatically.)

Upvotes: 6

Related Questions