withInMemoryScrolling in Angular: Modern Scroll Restoration and Anchor Scrolling Explained

Published: (January 14, 2026 at 08:30 AM EST)
5 min read
Source: Dev.to

Source: Dev.to

Introduction

Single‑page applications (SPAs) fundamentally changed web navigation by eliminating full page reloads. However, this architectural shift introduced a UX regression: browsers lost their native ability to restore scroll positions when users navigate backward or forward through history.

In traditional multi‑page applications, the browser automatically remembers where you scrolled on a page and returns you to that exact position when you hit the back button. SPAs broke this behavior.

Angular’s withInMemoryScrolling router feature addresses this gap by giving the router control over scroll behavior during navigation. It provides declarative configuration for two critical scroll‑related features:

  • Scroll position restoration across route changes.
  • Fragment‑based anchor scrolling.

Why you should care

If your app frequently navigates between routes and users expect intuitive scroll behavior—think content‑heavy sites, e‑commerce list‑detail pages, dashboards with tabbed interfaces, or any application where preserving navigation context improves usability—this feature is essential.

What Is withInMemoryScrolling?

withInMemoryScrolling is a router‑feature function introduced in Angular’s standalone‑API era. It enables the router to manage scroll behavior during navigation events. The “in‑memory” designation refers to how Angular stores scroll positions: it maintains a map of scroll positions in memory, keyed by navigation state, rather than relying on browser‑native mechanisms.

How it works

  1. Navigation start – the router captures the current scroll position.
  2. Navigation end – based on the configuration, the router decides to:
    • restore a previous position,
    • scroll to the top,
    • scroll to an anchor (fragment), or
    • leave the scroll unchanged.

The decision depends on options such as scrollPositionRestoration and anchorScrolling, as well as the navigation context (forward navigation, back navigation, route reload, etc.).

Browser default vs. Angular router‑controlled scrolling

AspectBrowser defaultAngular router‑controlled
ScopeDocument‑level, may be unreliable when the DOM is replaced.Operates within the router lifecycle, aware of lazy loading and route transitions.
DeterminismCan be inconsistent in SPAs.Provides deterministic behavior across all navigation scenarios.
CustomizationLimited.Fully configurable via withInMemoryScrolling.

Setting It Up (Standalone API)

Basic configuration

import { ApplicationConfig } from '@angular/core';
import { provideRouter, withInMemoryScrolling } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(
      routes,
      withInMemoryScrolling({
        scrollPositionRestoration: 'enabled', // or 'disabled' | 'top'
        anchorScrolling: 'enabled'            // or 'disabled'
      })
    )
  ]
};

Standalone bootstrap approach

import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withInMemoryScrolling } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(
      routes,
      withInMemoryScrolling({
        scrollPositionRestoration: 'enabled',
        anchorScrolling: 'enabled'
      })
    )
  ]
});

Configuration Options

OptionTypeDescription
scrollPositionRestoration'disabled' | 'enabled' | 'top'Controls how scroll positions are managed during navigation.
anchorScrolling'enabled' | 'disabled'Enables/disables automatic scrolling to fragment identifiers (#anchor).

scrollPositionRestoration values

ValueBehaviourTypical Use CasesUX Implications
disabledNo scroll management; the page stays where it was during navigation.* Custom scroll logic
* Infinite‑scroll components that manage their own position
* Single‑route apps where restoration isn’t needed
* Performance‑critical apps minimizing router overhead
Users navigating back will see the top of the previous page, which can feel disorienting in list‑detail patterns.
enabledRestores the previous scroll position on back/forward navigation; scrolls to top on new forward navigations.* E‑commerce product listings
* CMS article pages
* Any list‑to‑detail navigation pattern
Provides an intuitive experience that matches traditional websites—users return to where they left off.
topAlways scrolls to the top of the page on every navigation, regardless of direction.* Landing‑page flows where each view should start at the top
* Wizard‑style step‑by‑step interfaces
Guarantees a fresh start on each route change, but loses context when navigating back.

Example: Disable scroll restoration

withInMemoryScrolling({
  scrollPositionRestoration: 'disabled'
});

Example: Enable scroll restoration

withInMemoryScrolling({
  scrollPositionRestoration: 'enabled'
});

Anchor Scrolling

When anchorScrolling is set to 'enabled', the router automatically scrolls to the element whose id matches the URL fragment (e.g., #section-2). This works together with scrollPositionRestoration—if you navigate back to a URL containing a fragment, the router will first restore the saved scroll position, then scroll to the anchor if needed.

withInMemoryScrolling({
  scrollPositionRestoration: 'enabled',
  anchorScrolling: 'enabled'
});

Full Article & Demo

  • Read the full article – a deep dive into the internals, edge cases, and performance considerations.
  • Explore the live demo – see the feature in action with different configuration combos.
  • Access the complete source code – clone, experiment, and adapt to your own projects.

Full Article →
Live Demo →
GitHub Repository →

Join the Conversation

  • Did this article spark new ideas or solve a real problem? Let me know!
  • Already using this technique? Share your experience.
  • Got questions, doubts, or your own twist on the approach? Drop them in the comments—let’s learn together!

Spread the Word

If this guide added value to your development journey:

  • Share it with your team, tech friends, or community—you never know who might need it right now.
  • Save it for future reference.

Happy coding! 🚀

Quick Reference & Resources

I regularly share hands‑on tutorials, clean‑code tips, scalable frontend architecture, and real‑world problem‑solving guides.

PlatformDescription
💼 LinkedInLet’s connect professionally
🎥 ThreadsShort‑form frontend insights
🐦 X (Twitter)Developer banter + code snippets
👥 BlueSkyStay up‑to‑date on frontend trends
🌟 GitHub ProjectsExplore code in action
🌐 WebsiteEverything in one place
📚 Medium BlogLong‑form content and deep‑dives
💬 Dev BlogFree long‑form content and deep‑dives
✉️ SubstackWeekly frontend stories & curated resources
🧩 PortfolioProjects, talks, and recognitions
✍️ HashnodeDeveloper blog posts & tech discussions
✍️ RedditDeveloper blog posts & tech discussions

🎉 If you found this article valuable

  • Leave a 👏 Clap
  • Drop a 💬 Comment
  • Hit 🔔 Follow for more weekly frontend insights

Let’s build cleaner, faster, and smarter web apps — together.

Stay tuned for more Angular tips, patterns, and performance tricks! 🧪🧠🚀

✨ Share Your Thoughts → 📣 Set Your Notification Preference

Back to Blog

Related posts

Read more »

Scroll Restoration in React Router

Introduction When building Single Page Applications SPAs with React Router, a common UX issue appears almost immediately: navigation changes the URL, but the p...