Files

@isa/utils/scroll-position

Utility library providing scroll position restoration and scroll-to-top functionality for Angular applications.

Overview

The @isa/utils/scroll-position library enables automatic scroll position preservation across route navigations and provides a reusable scroll-to-top button component. It stores scroll positions in session storage and restores them when users navigate back to previously visited routes, creating a smoother user experience for applications with long, scrollable content.

Key Features:

  • Automatic Scroll Restoration: Preserve and restore scroll position across route navigation
  • Session Storage Integration: Persists scroll positions in session storage for reliability
  • Route-Level Control: Enable/disable restoration per route via route data configuration
  • Scroll-to-Top Button: Ready-to-use component with accessibility support
  • Configurable Delays: Control timing of scroll restoration with optional delays

Type: Utility library with functions, providers, and components

Installation

import {
  provideScrollPositionRestoration,
  injectRestoreScrollPosition,
  storeScrollPosition,
  ScrollTopButtonComponent
} from '@isa/utils/scroll-position';

API Reference

Providers

provideScrollPositionRestoration()

Provides an environment initializer that automatically stores scroll positions during navigation and page unload events.

Returns: EnvironmentProviders

Behavior:

  • Listens to NavigationStart events from the Angular Router
  • Listens to the beforeunload window event
  • Only stores scroll position for routes with scrollPositionRestoration: true in their route data
  • Stores positions in session storage using the current URL as the key

Usage:

// In app.config.ts
import { provideScrollPositionRestoration } from '@isa/utils/scroll-position';

export const appConfig: ApplicationConfig = {
  providers: [
    provideScrollPositionRestoration(),
    // other providers...
  ]
};

Functions

storeScrollPosition()

Stores the current viewport scroll position in session storage using the current router URL as the key.

Returns: Promise<void>

Usage:

import { Component } from '@angular/core';
import { storeScrollPosition } from '@isa/utils/scroll-position';

@Component({
  selector: 'app-product-list',
  // ...
})
export class ProductListComponent {
  async onNavigateAway() {
    // Manually store scroll position before navigating
    await storeScrollPosition();
    // navigation logic...
  }
}

injectRestoreScrollPosition()

Returns a function that restores the scroll position from session storage for the current route.

Returns: (delay?: number) => Promise<void> - An async function that accepts an optional delay parameter

Parameters (returned function):

  • delay?: number - Optional delay in milliseconds before restoring scroll position (default: 0)

Behavior:

  • Retrieves stored scroll position using the current router URL as the key
  • Waits for the specified delay to ensure the DOM is ready
  • Clears the stored position after restoration
  • Does nothing if no position was stored for the current URL

Usage:

import { Component, OnInit } from '@angular/core';
import { injectRestoreScrollPosition } from '@isa/utils/scroll-position';

@Component({
  selector: 'app-product-list',
  // ...
})
export class ProductListComponent implements OnInit {
  private restoreScrollPosition = injectRestoreScrollPosition();

  async ngOnInit() {
    // Restore scroll position after 100ms to ensure content is rendered
    await this.restoreScrollPosition(100);
  }
}

Components

ScrollTopButtonComponent

A standalone component that displays a button to scroll back to the top of the page or a specific scrollable element.

Selector: utils-scroll-top-button

Inputs:

  • target: Window | HTMLElement - The scroll target (default: window)

Features:

  • Automatically shows/hides based on scroll position (shows when scrolled down)
  • Respects user's prefers-reduced-motion setting
  • Uses smooth scrolling when motion is not reduced
  • Includes proper accessibility attributes (aria-label)
  • E2E testing ready with data-what attribute

Styling:

  • Host class: utils-scroll-top-button
  • Uses ViewEncapsulation.None for flexible styling
  • Button uses tertiary color and large size from @isa/ui/buttons

Usage:

// Basic usage (scrolls window)
import { ScrollTopButtonComponent } from '@isa/utils/scroll-position';

@Component({
  selector: 'app-product-list',
  imports: [ScrollTopButtonComponent],
  template: `
    <div class="content">
      <!-- Your scrollable content -->
    </div>
    <utils-scroll-top-button />
  `
})
export class ProductListComponent {}
// Custom scroll target (specific element)
@Component({
  selector: 'app-modal',
  imports: [ScrollTopButtonComponent],
  template: `
    <div #scrollContainer class="modal-content">
      <!-- Long content -->
    </div>
    <utils-scroll-top-button [target]="scrollContainer" />
  `
})
export class ModalComponent {
  @ViewChild('scrollContainer') scrollContainer!: ElementRef<HTMLElement>;
}

Styling Example:

// Custom positioning and appearance
utils-scroll-top-button {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  z-index: 1000;
}

Usage Examples

Complete Setup with Automatic Restoration

// 1. Configure in app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideScrollPositionRestoration } from '@isa/utils/scroll-position';

export const appConfig: ApplicationConfig = {
  providers: [
    provideScrollPositionRestoration(),
  ]
};

// 2. Enable in route configuration
export const routes: Routes = [
  {
    path: 'products',
    component: ProductListComponent,
    data: { scrollPositionRestoration: true }
  }
];

// 3. Restore position in component
import { Component, OnInit } from '@angular/core';
import { injectRestoreScrollPosition, ScrollTopButtonComponent } from '@isa/utils/scroll-position';

@Component({
  selector: 'app-product-list',
  imports: [ScrollTopButtonComponent],
  template: `
    <div class="product-grid">
      @for (product of products(); track product.id) {
        <app-product-card [product]="product" />
      }
    </div>
    <utils-scroll-top-button />
  `
})
export class ProductListComponent implements OnInit {
  private restoreScrollPosition = injectRestoreScrollPosition();

  async ngOnInit() {
    await this.loadProducts();
    // Restore scroll after content loads
    await this.restoreScrollPosition(100);
  }
}

Manual Control for Custom Scenarios

import { Component } from '@angular/core';
import { storeScrollPosition, injectRestoreScrollPosition } from '@isa/utils/scroll-position';

@Component({
  selector: 'app-custom-navigation',
  // ...
})
export class CustomNavigationComponent {
  private restoreScrollPosition = injectRestoreScrollPosition();

  async onCustomNavigateAway() {
    // Store before custom navigation logic
    await storeScrollPosition();
    this.customNavigationService.navigate();
  }

  async onCustomNavigateBack() {
    // Restore after returning
    await this.restoreScrollPosition(200);
  }
}

Route Configuration

To enable automatic scroll restoration on specific routes, add the scrollPositionRestoration property in route data:

export const routes: Routes = [
  {
    path: 'example',
    component: ExampleComponent,
    data: {
      scrollPositionRestoration: true
    }
  }
];

Dependencies

  • @angular/common - ViewportScroller for scroll operations
  • @angular/core - Core Angular functionality (inject, signals, etc.)
  • @angular/router - Router integration for navigation events
  • @isa/core/storage - Session storage provider for persistence
  • @isa/ui/buttons - Icon button component for ScrollTopButtonComponent
  • @isa/icons - Icon assets (isaSortByUpMedium)
  • @ng-icons/core - Icon system integration

Notes

  • Scroll positions are stored in session storage and cleared after restoration
  • The automatic restoration only applies to routes with scrollPositionRestoration: true in their data
  • The scroll-to-top button respects accessibility preferences (prefers-reduced-motion)
  • Manual restoration includes a configurable delay to ensure DOM readiness before scrolling
  • The scroll-to-top button automatically shows/hides based on scroll position