DEV Community

Cover image for Support for in/inter page linking / scrolling in EmberJS
Michal Bryxí
Michal Bryxí

Posted on

1

Support for in/inter page linking / scrolling in EmberJS

The problem

Navigating to URLs with #hash-targets in them is not supported by most single-page-app frameworks due to the async rendering nature of modern web apps -- the browser can't scroll to a #hash-target on page load / transition because the element hasn't rendered yet. There is an issue about this for Ember here on the RFCs repo.

Solution

ember-url-hash-polyfill

The addon ember-url-hash-polyfill provides a way to support the behaviour that is in normally native to browsers where an anchor tag with href="#some-id-or-name" would scroll down the page when clicked.

The problem with ember-url-hash-polyfill solution is that it skips the use of <LinkTo> in favour of native HTML <a> tag. If you can't/don't want do that, the next section is for you.

ember-scroll-modifiers

The ember-scroll-modifiers addon offers scroll-into-view modifier which can be used here. Drawback being that we won't be using hash property of the URL, but rather query-param.

First we need to define our query param which will be named scrollTo and will live on application controller, so that we have access to it from every route:

// controllers/application.ts
import { service } from '@ember/service';
import type ScrollService from 'my-app/services/scroll';

export default class ApplicationController extends Controller {
  @service declare scroll: ScrollService;

  queryParams = ['scrollTo'];
}
Enter fullscreen mode Exit fullscreen mode

Then we will create scroll service which will be able to tell us which scrollTo was activated:

// services/scroll.ts

export default class ScrollService extends Service {
  @service declare router: RouterService;

  get inView() {
    return this.router.currentRoute.queryParams['scrollTo'];
  }

  get heroInView() { // cheap example, add yours to expand
    return this.inView === 'hero';
  }
}
Enter fullscreen mode Exit fullscreen mode

And finally and example of template that defines a link with scrollTo query parameter. And an element that we wish to scroll to marked with scroll-int-view modifier.

// templates/application.hbs

<LinkTo
  @route="index"
  @query={{hash scrollTo="hero"}}
>
  Link to Hero
</LinkTo>

...

<div
  {{scroll-into-view
    shouldScroll=this.scroll.heroInView
    options=(hash behavior="smooth")
  }}
>
  I am hero!
</div>
Enter fullscreen mode Exit fullscreen mode

Nice thing is that we can also invoke route transition & scrollTo programatically via router service transitionTo:

this.router.transitionTo('index', {
  queryParams: { scrollTo: 'hero' },
});
Enter fullscreen mode Exit fullscreen mode

Cover image generated via Midjourney prompt: scrolling in web browser --ar 16:9

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay