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

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up