Row Expansion (Sub rows)

Row expansion enables tables to display hierarchical data by allowing rows to expand and reveal nested sub-rows. This is useful for representing parent-child relationships, grouped data, or tree structures within a table.

The demo below shows a table with expandable rows containing nested data. Each row with children displays an expand button that toggles visibility of its sub-rows. The header includes an expand-all button that expands or collapses all rows at once. Visual indentation indicates the depth level of each row in the hierarchy.

Username
Account Status Role Avg Session Duration Company Name Last Visited At Visit Count
Cara.Gislason37
pending admin 119 Will - Collins 27 Dec 2024 01:51:32 PDT 418
Earline_Heidenreich
suspended admin 118 Adams, Blanda and Lang 12 Sep 2025 08:23:20 PDT 2
Dina.Hammes60
active user 119 Cruickshank Inc 26 Nov 2024 06:52:05 PDT 4
Jayda_Prosacco55
pending user 23 Lindgren, Runolfsdottir and Ernser 25 Feb 2025 20:35:32 PDT 18
Antonio.McDermott46
pending user 119 Dooley - Ruecker 07 Jun 2025 10:19:14 PDT 117
Myrl_Waelchi
active moderator 100 Harvey and Sons 03 Apr 2025 01:40:14 PDT 3
Elyssa.Lesch
suspended user 119 Medhurst, Schulist and Gutmann 16 Jul 2025 14:37:21 PDT 182
Nils_Spinka
pending user 92 Beer Inc 26 Aug 2024 12:27:41 PDT 3
Karli_Larkin
active moderator 119 Abernathy - Stiedemann 16 Aug 2025 22:48:10 PDT 2
Chandler.Barrows
suspended admin 116 Casper, Marvin and Lebsack 12 Nov 2024 18:10:12 PDT 2
import {Component} from "@angular/core"

import {ButtonModule} from "@qualcomm-ui/angular/button"
import {PaginationModule} from "@qualcomm-ui/angular/pagination"
import {ProgressRingModule} from "@qualcomm-ui/angular/progress-ring"
import {
  createAngularTable,
  createTablePagination,
  TableModule,
} from "@qualcomm-ui/angular/table"
import {
  getCoreRowModel,
  getExpandedRowModel,
  getPaginationRowModel,
} from "@qualcomm-ui/core/table"

import {createUserQuery, type User, userColumns} from "./data"

@Component({
  imports: [TableModule, PaginationModule, ButtonModule, ProgressRingModule],
  selector: "row-expansion-demo",
  template: `
    <div q-table-root>
      <div q-table-action-bar>
        <button
          q-button
          size="sm"
          variant="outline"
          [disabled]="query.isFetching()"
          (click)="query.refetch()"
        >
          Refresh Data
        </button>
        @if (query.isFetching()) {
          <div q-progress-ring size="xs"></div>
        }
      </div>
      <div q-table-scroll-container>
        <table q-table-table>
          <thead q-table-header>
            @for (
              headerGroup of table.getHeaderGroups();
              track headerGroup.id
            ) {
              <tr q-table-row>
                @for (header of headerGroup.headers; track header.id) {
                  <th q-table-header-cell>
                    <ng-container *renderHeader="header; let value">
                      {{ value }}
                    </ng-container>
                  </th>
                }
              </tr>
            }
          </thead>
          <tbody q-table-body>
            @for (row of table.getRowModel().rows; track row.id) {
              <tr q-table-row>
                @for (cell of row.getVisibleCells(); track cell.id) {
                  <td q-table-cell>
                    <ng-container *renderCell="cell; let value">
                      {{ value }}
                    </ng-container>
                  </td>
                }
              </tr>
            }
          </tbody>
        </table>
      </div>
      <div
        q-table-pagination
        [count]="pagination.count()"
        [page]="pagination.page()"
        [pageSize]="pagination.pageSize()"
        (pageChanged)="pagination.onPageChange($event)"
      >
        <div *paginationContext="let context" q-pagination-page-metadata>
          @let meta = context.pageMetadata;
          {{ meta.pageStart }}-{{ meta.pageEnd }} of {{ meta.count }} results
        </div>

        <div q-pagination-page-buttons></div>
      </div>
    </div>
  `,
})
export class RowExpansionDemo {
  protected readonly query = createUserQuery(100, 5, 3)

  protected table = createAngularTable<User>(() => ({
    columns: userColumns,
    data: this.query.data() || [],
    getCoreRowModel: getCoreRowModel(),
    getExpandedRowModel: getExpandedRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSubRows: (row: User) => row.subRows,
  }))

  protected pagination = createTablePagination(this.table)
}
Last updated on by Ryan Bower