iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Lists / Virtual Scroll

Ionic lists with ion-list, ion-item, sliding actions, reorder, and virtual scroll. The patterns you reach for daily.

Ionic — lists

EXAMPLE
<!-- ===== 1. Basic list ===== -->
<ion-list>
  <ion-item *ngFor="let user of users">
    <ion-avatar slot="start"><img [src]="user.avatar" alt=""></ion-avatar>
    <ion-label>
      <h2>{{ user.name }}</h2>
      <p>{{ user.email }}</p>
    </ion-label>
    <ion-note slot="end">{{ user.lastSeen | date:'shortTime' }}</ion-note>
  </ion-item>
</ion-list>

<!-- ===== 2. Grouped list with dividers ===== -->
<ion-list>
  <ion-list-header>Online</ion-list-header>
  <ion-item *ngFor="let u of online">{{ u.name }}</ion-item>

  <ion-item-divider></ion-item-divider>

  <ion-list-header>Offline</ion-list-header>
  <ion-item *ngFor="let u of offline" color="light">{{ u.name }}</ion-item>
</ion-list>

<!-- ===== 3. Sliding actions (swipe to reveal) ===== -->
<ion-list>
  <ion-item-sliding *ngFor="let m of messages">
    <ion-item>
      <ion-label>
        <h3>{{ m.subject }}</h3>
        <p>{{ m.preview }}</p>
      </ion-label>
    </ion-item>
    <ion-item-options side="end">
      <ion-item-option (click)="archive(m)">Archive</ion-item-option>
      <ion-item-option color="danger" (click)="remove(m)">Delete</ion-item-option>
    </ion-item-options>
  </ion-item-sliding>
</ion-list>

<!-- ===== 4. Reorder ===== -->
<ion-reorder-group (ionItemReorder)="onReorder($event)" disabled="false">
  <ion-item *ngFor="let t of tasks">
    <ion-label>{{ t.title }}</ion-label>
    <ion-reorder slot="end"></ion-reorder>
  </ion-item>
</ion-reorder-group>

<!-- ===== 5. Pull-to-refresh + Infinite scroll ===== -->
<ion-content [scrollEvents]="true">
  <ion-refresher slot="fixed" (ionRefresh)="refresh($event)">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>

  <ion-list>
    <ion-item *ngFor="let p of products">{{ p.name }}</ion-item>
  </ion-list>

  <ion-infinite-scroll (ionInfinite)="loadMore($event)">
    <ion-infinite-scroll-content loadingSpinner="bubbles" loadingText="Loading more…">
    </ion-infinite-scroll-content>
  </ion-infinite-scroll>
</ion-content>

<!-- ===== Handlers ===== -->
<!-- onReorder(ev: any) { this.tasks = ev.detail.complete(this.tasks); } -->
<!-- async refresh(ev: any) { this.products = await this.api.list(); ev.target.complete(); } -->
<!-- async loadMore(ev: any) { const page = await this.api.list({ page: this.next }); ... ev.target.complete(); if (page.length < 20) ev.target.disabled = true; } -->

<!-- ===== 6. Virtual scroll for very long lists (Angular CDK) ===== -->
<cdk-virtual-scroll-viewport itemSize="56" style="height: 100vh">
  <ion-item *cdkVirtualFor="let row of bigList">{{ row.title }}</ion-item>
</cdk-virtual-scroll-viewport>

<!-- ===== Patterns to internalise =====
- Use ion-list-header / ion-item-divider for clean section breaks; both render reliably across platforms
- ion-item-sliding for destructive actions; pair colour=danger with an immediate confirm or undo
- Pair ion-refresher with ion-infinite-scroll for a complete refresh + paginate flow
- Reach for cdk-virtual-scroll only when the list is genuinely large; otherwise *ngFor is fine
- Use ion-skeleton-text while data is loading; avoids layout jumps

===== Pitfalls =====
- Forgetting ev.target.complete() on refresher/infinite-scroll -> spinner stays forever
- ion-item-sliding without enough slop distance -> users miss the swipe
- Mixing ion-list and a non-ionic list inside scrollable area -> double scroll surfaces
- Reorder enabled by default on read-only lists -> users accidentally drag rows
- Custom heights breaking virtual scroll's itemSize assumption -> jumping scrollbars
-->

Why it matters

Lists are 70% of mobile UI. Ion-list + ion-item give you the look; sliding actions, reorder, refresher, and infinite scroll cover the interactions. Reach for virtual scroll only when the rows justify it. These five patterns ship most app screens with very little code.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
<ion-list>
    <ion-item *ngFor="let u of users">
        <ion-label>
            <h2>{{ u.name }}</h2>
            <p>{{ u.email }}</p>
        </ion-label>
    </ion-item>
</ion-list>
Try it Yourself »

Discussion

Loading…