<viewpager>

Full-width pages the user swipes between horizontally, like a carousel or an onboarding flow.

Usage

src/app/onboarding.ts
import { Component, signal } from '@angular/core';
import { LYNX_ELEMENTS } from '@blotch/angular-lynx';

@Component({
  selector: 'app-onboarding',
  imports: [LYNX_ELEMENTS],
  template: `
    <viewpager
      style="width: 100%; height: 300px;"
      (bindchange)="onChange($event)"
    >
      @for (page of pages; track page) {
        <viewpager-item>
          <text>{{ page }}</text>
        </viewpager-item>
      }
    </viewpager>
    <text>Page {{ current() + 1 }} of {{ pages.length }}</text>
  `,
})
export class Onboarding {
  readonly pages = ['Welcome', 'Sync', 'Done'];
  readonly current = signal(0);

  onChange(event: Event): void {
    this.current.set((event as CustomEvent<{ index: number }>).detail.index);
  }
}

Import LYNX_ELEMENTS in your component (see Elements).

Warning

Needs XElement in custom native apps (see Embedding).

Attributes

AttributeTypeDefaultDescription
initial-select-indexnumber0Page shown first.
enable-scrollbooleantrueWhether the user can swipe between pages.
bouncesbooleantrueiOS only. Bounce past the first and last pages.
keep-item-viewbooleanfalseiOS and Android. Keeps the views of off-screen pages attached instead of releasing them.
android-always-overscrollbooleanfalseAndroid only. Bounce past the first and last pages.
android-force-can-scrollbooleanfalseAndroid only. At the first and last pages, keeps the swipe from passing to a parent.
ios-gesture-directionbooleanfalseiOS only. At the first and last pages, lets an outer horizontal scroll view take the swipe.
ios-gesture-offsetnumber0iOS only. Width in px of a strip at the left edge where the pager ignores swipes, so the system swipe-back gesture works there.
ios-recognized-gesture-classstring—iOS only. Class name of a native gesture recognizer in the host app that may run at the same time as the pager.
ios-recognized-view-tagnumber0iOS only. Tag of the native view that owns that gesture recognizer.

Plus the common attributes, such as id, class and style.

Events

Read the payload from $event.detail (see Handling taps and events).

EventdetailDescription
bindchange{ index: number; isDragged: boolean }The pager settled on page index. isDragged is true when the user swiped there.
bindwillchange{ index: number; isDragged: boolean }The pager is about to move to page index.
bindoffsetchange{ offset: number }Fires during a swipe. offset is the position in pages: 0.5 is halfway between pages 0 and 1.

Plus the common events, such as bindtap.

Methods

This UI method (Glossary) changes the page from code. Call it with invoke() on the element (see Call element methods).

MethodParametersDescription
selectTab{ index: number; smooth?: boolean }Moves to page index. It animates unless smooth is false.
import { Component, ElementRef, viewChild } from '@angular/core';
import { LYNX_ELEMENTS } from '@blotch/angular-lynx';

@Component({
  selector: 'app-slides',
  imports: [LYNX_ELEMENTS],
  template: `
    <viewpager #pager style="width: 100%; height: 300px;">
      <viewpager-item><text>One</text></viewpager-item>
      <viewpager-item><text>Two</text></viewpager-item>
    </viewpager>
    <view (bindtap)="next()"><text>Next</text></view>
  `,
})
export class Slides {
  readonly pager = viewChild.required('pager', { read: ElementRef });

  next(): void {
    this.pager().nativeElement.invoke?.('selectTab', { index: 1 });
  }
}

Children

Wrap each page in a <viewpager-item>. Every direct child must be one.