TreeTable

TreeTable is used to display hierarchical data in tabular format.


import { TreeTableModule } from 'primeng/treetable';

TreeTable requires a collection of TreeNode instances as a value components as children for the representation.


<p-treeTable [value]="files" [scrollable]="true" [tableStyle]="{'min-width':'50rem'}">
    <ng-template pTemplate="header">
        <tr>
            <th>Name</th>
            <th>Size</th>
            <th>Type</th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
        <tr [ttRow]="rowNode">
            <td>
                <p-treeTableToggler [rowNode]="rowNode" />
                {{ rowData.name }}
            </td>
            <td>{{ rowData.size }}</td>
            <td>{{ rowData.type }}</td>
        </tr>
    </ng-template>
</p-treeTable>

Columns can be created programmatically.


<p-treeTable [value]="files" [columns]="cols" [scrollable]="true" [tableStyle]="{'min-width':'50rem'}">
    <ng-template pTemplate="header" let-columns>
        <tr>
            <th *ngFor="let col of columns">
                {{ col.header }}
            </th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
        <tr [ttRow]="rowNode">
            <td *ngFor="let col of columns; let i = index">
                <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                {{ rowData[col.field] }}
            </td>
        </tr>
    </ng-template>
</p-treeTable>

Expansion state is controlled with expandedKeys property.


<p-button (onClick)="toggleApplications()" label="Toggle Applications" />
<p-treeTable [value]="files" [scrollable]="true" [tableStyle]="{ 'min-width': '50rem' }" styleClass="mt-4">
    <ng-template pTemplate="header">
        <tr>
            <th>Name</th>
            <th>Size</th>
            <th>Type</th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
        <tr [ttRow]="rowNode">
            <td>
                <p-treeTableToggler [rowNode]="rowNode" />
                {{ rowData.name }}
            </td>
            <td>{{ rowData.size }}</td>
            <td>{{ rowData.type }}</td>
        </tr>
    </ng-template>
</p-treeTable>

Custom content at caption, header, body and summary sections are supported via templating.


<p-treeTable [value]="files" [columns]="cols" [scrollable]="true" [tableStyle]="{ 'min-width': '50rem' }">
        <ng-template pTemplate="caption"><div class="text-xl font-bold">File Viewer</div> </ng-template>
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index; let last = last">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                    <ng-container *ngIf="last">
                        <p-button icon="pi pi-search" rounded="true" [style]="{ 'margin-right': '.5em' }" />
                        <p-button icon="pi pi-pencil" rounded="true" severity="success" />
                    </ng-container>
                </td>
            </tr>
        </ng-template>
        <ng-template pTemplate="summary">
            <div style="text-align:left">
                <p-button icon="pi pi-refresh" label="Reload" severity="warning" />
            </div>
        </ng-template>
</p-treeTable>

In addition to a regular treetable, alternatives with alternative sizes are available. Add p-treetable-sm class to reduce the size of treetable or p-treetable-lg to enlarge it.


<div class="flex justify-content-center mb-3">
    <p-selectButton 
        [options]="sizes" 
        [(ngModel)]="selectedSize" 
        [multiple]="false" 
        optionLabel="name" 
        optionValue="class" />
</div>
<p-treeTable 
    [value]="files" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}" 
    [styleClass]="selectedSize">
        <ng-template pTemplate="header">
            <tr>
                <th>Name</th>
                <th>Size</th>
                <th>Type</th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
            <tr [ttRow]="rowNode">
                <td>
                    <p-treeTableToggler [rowNode]="rowNode" />
                    {{ rowData.name }}
                </td>
                <td>{{ rowData.size }}</td>
                <td>{{ rowData.type }}</td>
            </tr>
        </ng-template>
</p-treeTable>

Adding p-treetable-gridlines class displays grid lines.


<p-treeTable 
    [value]="files" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}" 
    styleClass="p-treetable-gridlines">
        <ng-template pTemplate="header">
            <tr>
                <th>Name</th>
                <th>Size</th>
                <th>Type</th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
            <tr [ttRow]="rowNode">
                <td>
                    <p-treeTableToggler [rowNode]="rowNode" />
                    {{ rowData.name }}
                </td>
                <td>{{ rowData.size }}</td>
                <td>{{ rowData.type }}</td>
            </tr>
        </ng-template>
</p-treeTable>

Pagination is enabled by adding paginator property and defining rows per page.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [paginator]="true" 
    [rows]="5" 
    [rowsPerPageOptions]="[5, 10, 25]" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Paginator localization information such as page numbers and rows per page options are defined with the paginatorLocale property which defaults to the user locale.


<p-treeTable 
    paginatorLocale="fa-IR" 
    [value]="files" 
    [columns]="cols" 
    [paginator]="true" 
    [rows]="10" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Paginator UI is customized using the paginatorleft and paginatorright property. Each element can also be customized further with your own UI to replace the default one, refer to the Paginator component for more information about the advanced customization options.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [paginator]="true" 
    [rows]="10" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
        <ng-template pTemplate="paginatorleft">
            <p-button icon="pi pi-refresh" styleClass="p-button-text" />
        </ng-template>
        <ng-template pTemplate="paginatorright">
            <p-button icon="pi pi-download" styleClass="p-button-text" />
        </ng-template>
</p-treeTable>

Sorting on a column is enabled by adding the ttSortableColumn property.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns" [ttSortableColumn]="col.field">
                    {{ col.header }}
                    <p-treeTableSortIcon [field]="col.field" />
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Multiple columns can be sorted by defining sortMode as multiple. This mode requires metaKey (e.g. ⌘) to be pressed when clicking a header.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    sortMode="multiple" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns" [ttSortableColumn]="col.field">
                    {{ col.header }}
                    <p-treeTableSortIcon [field]="col.field" />
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

The filterMode specifies the filtering strategy, in lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other hand, in strict mode when the query matches a node, filtering continues on all descendants. A general filled called filterGlobal is also provided to search all columns that support filtering.

Lenient
Strict

<p-selectButton 
    [options]="filterModes" 
    [(ngModel)]="filterMode" 
    optionLabel="label" 
    optionValue="value" />

<p-treeTable 
    #tt 
    [value]="files" 
    [columns]="cols" 
    [filterMode]="filterMode" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="caption">
            <div class="flex justify-content-end align-items-center">
                <div class="p-input-icon-left">
                    <i class="pi pi-search"></i>
                    <input 
                        type="text" 
                        pInputText 
                        placeholder="Global Search" 
                        (input)="tt.filterGlobal($event.target.value, 'contains')" />
                </div>
            </div>
        </ng-template>
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of cols">
                    {{ col.header }}
                </th>
            </tr>
            <tr>
                <th *ngFor="let col of cols">
                    <input 
                        pInputText 
                        type="text" 
                        (input)="tt.filter($event.target.value, col.field, col.filterMatchMode)" />
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of cols; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
        <ng-template pTemplate="emptymessage">
            <tr>
                <td [attr.colspan]="cols.length">No data found.</td>
            </tr>
        </ng-template>
</p-treeTable>

Single node selection is configured by setting selectionMode as single along with selection properties to manage the selection value binding.

By default, metaKey press (e.g. ⌘) is necessary to unselect a node however this can be configured with disabling the metaKeySelection property. In touch enabled devices this option has no effect and behavior is same as setting it to false

Metakey

<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    selectionMode="single" 
    [(selection)]="selectedNode" 
    dataKey="name" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" [ttSelectableRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

More than one node is selectable by setting selectionMode to multiple. By default in multiple selection mode, metaKey press (e.g. ⌘) is necessary to add to existing selections however this can be configured with disabling the metaKeySelection property. Note that in touch enabled devices, TreeTable always ignores metaKey.

Metakey

<p-inputSwitch [(ngModel)]="metaKeySelection" />
<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    selectionMode="multiple" 
    [(selection)]="selectedNodes" 
    dataKey="name" 
    [metaKeySelection]="metaKeySelection" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" [ttSelectableRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Selection of multiple nodes via checkboxes is enabled by configuring selectionMode as checkbox.

In checkbox selection mode, value binding should be a key-value pair where key (or the dataKey) is the node key and value is an object that has checked and partialChecked properties to represent the checked state of a node.


{
    '0-0': {
        partialChecked: false,
        checked: true
    }
}


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    selectionMode="checkbox" 
    [(selectionKeys)]="selectionKeys" 
    dataKey="key" 
    [scrollable]="true" 
    [tableStyle]="{ 'min-width': '50rem' }">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" [ttSelectableRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    <p-treeTableCheckbox [value]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

TreeTable provides onNodeSelect and onNodeUnselect events to listen selection events.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    selectionMode="single" 
    [(selection)]="selectedNode" 
    dataKey="name" 
    (onNodeSelect)="nodeSelect($event)" 
    (onNodeUnselect)="nodeUnselect($event)" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" [ttSelectableRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>


<p-treeTable [value]="sales" [scrollable]="true" [tableStyle]="{'min-width':'50rem'}">
    <ng-template pTemplate="header">
        <tr>
            <th rowspan="3">Brand</th>
            <th colspan="4">Sale Rate</th>
        </tr>
        <tr>
            <th colspan="2">Sales</th>
            <th colspan="2">Profits</th>
        </tr>
        <tr>
            <th>Last Year</th>
            <th>This Year</th>
            <th>Last Year</th>
            <th>This Year</th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
        <tr>
            <td>
                <p-treeTableToggler [rowNode]="rowNode" />
                {{ rowData.brand }}
            </td>
            <td>{{ rowData.lastYearSale }}</td>
            <td>{{ rowData.thisYearSale }}</td>
            <td>{{ rowData.lastYearProfit }}</td>
            <td>{{ rowData.thisYearProfit }}</td>
        </tr>
    </ng-template>
    <ng-template pTemplate="footer">
        <tr>
            <td colspan="3">Totals</td>
            <td>$3,283,772</td>
            <td>$2,126,925</td>
        </tr>
    </ng-template>
</p-treeTable>

Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking corresponding callbacks everytime paging, sorting and filtering occurs. Sample below imitates lazy loading data from a remote datasource using an in-memory list and timeouts to mimic network connection.

Enabling the lazy property and assigning the logical number of rows to totalRecords by doing a projection query are the key elements of the implementation so that paginator displays the UI assuming there are actually records of totalRecords size although in reality they are not present on page, only the records that are displayed on the current page exist.

In addition, only the root elements should be loaded, children can be loaded on demand using onNodeExpand callback.

Name Size Type
Item 0 335kb Type 0
Item 1 690kb Type 1
Item 2 833kb Type 2
Item 3 749kb Type 3
Item 4 120kb Type 4
Item 5 500kb Type 5
Item 6 867kb Type 6
Item 7 754kb Type 7
Item 8 806kb Type 8
Item 9 410kb Type 9

<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [paginator]="true" 
    [rows]="10" 
    [lazy]="true" 
    (onLazyLoad)="loadNodes($event)" 
    [totalRecords]="1000" 
    [loading]="loading" 
    (onNodeExpand)="onNodeExpand($event)" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Incell editing is enabled by defining input elements with treeTableCellEditor.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index" ttEditableColumn [ttEditableColumnDisabled]="i == 0" [ngClass]="{ 'p-toggler-column': i === 0 }">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    <p-treeTableCellEditor>
                        <ng-template pTemplate="input">
                            <input pInputText type="text" [(ngModel)]="rowData[col.field]" />
                        </ng-template>
                        <ng-template pTemplate="output">
                            {{ rowData[col.field] }}
                        </ng-template>
                    </p-treeTableCellEditor>
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Adding scrollable property along with a scrollHeight for the data viewport enables vertical scrolling with fixed headers.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [scrollable]="true" 
    scrollHeight="200px" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Flex scroll feature makes the scrollable viewport section dynamic instead of a fixed value so that it can grow or shrink relative to the parent size of the table. Click the button below to display a maximizable Dialog where data viewport adjusts itself according to the size changes.


<p-button label="Show" icon="pi pi-external-link" (onClick)="dialogVisible = true" />
<p-dialog 
    [(visible)]="dialogVisible" 
    header="Flex Scroll" 
    [style]="{ width: '75vw' }" 
    maximizable 
    modal 
    [contentStyle]="{ height: '300px' }">
        <ng-template pTemplate="content">
            <p-treeTable 
                [value]="files" 
                [scrollable]="true" 
                scrollHeight="flex" 
                [tableStyle]="{ 'min-width': '50rem' }">
                    <ng-template pTemplate="header">
                        <tr>
                            <th>Name</th>
                            <th>Size</th>
                            <th>Type</th>
                        </tr>
                    </ng-template>
                    <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
                        <tr [ttRow]="rowNode">
                            <td>
                                <p-treeTableToggler [rowNode]="rowNode" />
                                {{ rowData.name }}
                            </td>
                            <td>
                                {{ rowData.size }}
                            </td>
                            <td>
                                {{ rowData.type }}
                            </td>
                        </tr>
                    </ng-template>
            </p-treeTable>
        </ng-template>
        <ng-template pTemplate="footer">
            <p-button label="Ok" icon="pi pi-check" (onClick)="dialogVisible = false" />
        </ng-template>
</p-dialog>

Horizontal scrolling is enabled when the total width of columns exceeds table width.


<p-treeTable [value]="files" [columns]="cols" [scrollable]="true" scrollHeight="200px" [scrollable]="true" [tableStyle]="{'min-width':'50rem'}">
    <ng-template pTemplate="colgroup" let-columns>
        <colgroup>
            <col *ngFor="let col of columns" style="width:500px" />
        </colgroup>
    </ng-template>
    <ng-template pTemplate="header" let-columns>
        <tr>
            <th *ngFor="let col of columns">
                {{ col.header }}
            </th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
        <tr [ttRow]="rowNode">
            <td *ngFor="let col of columns; let i = index">
                <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0"></p-treeTableToggler>
                {{ rowData[col.field] }}
            </td>
        </tr>
    </ng-template>
</p-treeTable>

A column can be fixed during horizontal scrolling by enabling the frozenColumns property.


<p-treeTable 
    [value]="files" 
    [columns]="scrollableCols" 
    [frozenColumns]="frozenCols" 
    [scrollable]="true" 
    scrollHeight="250px" 
    frozenWidth="200px" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="colgroup" let-columns>
            <colgroup>
                <col *ngFor="let col of columns" style="width:250px" />
            </colgroup>
        </ng-template>
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" style="height: 57px">
                <td *ngFor="let col of columns; let i = index">
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
        <ng-template pTemplate="frozenbody" let-rowNode let-rowData="rowData">
            <tr [ttRow]="rowNode" style="height: 57px">
                <td>
                    <p-treeTableToggler [rowNode]="rowNode" />
                    {{ rowData.name }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Columns can be resized with drag and drop when resizableColumns is enabled. Default resize mode is fit that does not change the overall table width.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [resizableColumns]="true" 
    [tableStyle]="{'min-width': '50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns" ttResizableColumn>
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Setting columnResizeMode as expand changes the table width as well.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [resizableColumns]="true" 
    columnResizeMode="expand">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns" ttResizableColumn>
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

To utilize the column resize modes with a scrollable TreeTable, a colgroup template must be defined. The default value of scrollHeight is "flex," it can also be set as a string value.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [resizableColumns]="true" 
    [scrollable]="true" 
    scrollHeight="200px">
        <ng-template pTemplate="colgroup" let-columns>
            <colgroup>
                <col *ngFor="let col of columns">
            </colgroup>
        </ng-template>
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns" ttResizableColumn>
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Order of the columns can be changed using drag and drop when reorderableColumns is present.


<p-treeTable [value]="files" [columns]="cols" [reorderableColumns]="true" [scrollable]="true" [tableStyle]="{'min-width':'50rem'}">
    <ng-template pTemplate="header" let-columns>
        <tr>
            <th *ngFor="let col of columns" ttReorderableColumn>
                {{ col.header }}
            </th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
        <tr [ttRow]="rowNode">
            <td *ngFor="let col of columns; let i = index">
                <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0"></p-treeTableToggler>
                {{ rowData[col.field] }}
            </td>
        </tr>
    </ng-template>
</p-treeTable>

Column visibility based on a condition can be implemented with dynamic columns, in this sample a MultiSelect is used to manage the visible columns.


<p-treeTable 
    [value]="files" 
    [columns]="selectedColumns" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="caption">
            <div style="text-align:left">
                <p-multiSelect 
                    [options]="cols" 
                    [(ngModel)]="selectedColumns"
                    optionLabel="header" 
                    selectedItemsLabel="{0} columns selected" 
                    [style]="{ width: '20em' }" 
                    defaultLabel="Choose Columns" display="chip" />
            </div>
        </ng-template>
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

Particular rows and cells can be styled based on conditions. The ngClass receives a row data as a parameter to return a style class for a row whereas cells are customized using the body template.


<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" [ngClass]="{ 'p-highlight': rowData.size.endsWith('kb') }">
                <td 
                    *ngFor="let col of columns; let i = index" 
                    [ngClass]="{ 'font-bold': col.field === 'size' && rowData.size.endsWith('kb') }">
                        <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                        {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

TreeTable has exclusive integration with ContextMenu using the contextMenu event to open a menu on right click alont with contextMenuSelection properties to control the selection via the menu.


<p-toast [style]="{ marginTop: '80px' }" />

<p-treeTable 
    [value]="files" 
    [columns]="cols" 
    dataKey="name" 
    [(contextMenuSelection)]="selectedNode" 
    [contextMenu]="cm" 
    [scrollable]="true" 
    [tableStyle]="{'min-width':'50rem'}">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{ col.header }}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" [ttContextMenuRow]="rowNode">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i === 0" />
                    {{ rowData[col.field] }}
                </td>
            </tr>
        </ng-template>
</p-treeTable>

<p-contextMenu #cm [model]="items" />

Following is the list of structural style classes, for theming classes visit theming page.

NameElement
p-treetableContainer element.
p-treetable-captionCaption element.
p-treetable-summarySection section.
p-sortable-columnSortable column header.
p-treetable-scrollable-headerContainer of header in a scrollable table.
p-treetable-scrollable-bodyContainer of body in a scrollable table.
p-treetable-scrollable-footerContainer of footer in a scrollable table.
p-treetable-loadingLoader mask.
p-treetable-loading-contentLoader content.
p-treetable-wrapperLoader content.
p-treetable-scrollable-wrapperLoader content.
p-treetable-resizer-helperVertical resize indicator bar.
p-treetable-reorder-indicator-topTop indicator of column reordering.
p-treetable-reorder-indicator-topBottom indicator of column reordering.

Screen Reader

Default role of the table is table. Header, body and footer elements use rowgroup, rows use row role, header cells have columnheader and body cells use cell roles. Sortable headers utilizer aria-sort attribute either set to "ascending" or "descending".

Row elements manage aria-expanded for state and aria-level attribute to define the hierachy by ttRow directive. Table rows and table cells should be specified by users using the aria-posinset, aria-setsize, aria-label, and aria-describedby attributes, as they are determined through templating.

When selection is enabled, ttSelectableRow directive sets aria-selected to true on a row. In checkbox mode, the built-in checkbox component use checkbox role with aria-checked state attribute.

Editable cells use custom templating so you need to manage aria roles and attributes manually if required.

Paginator is a standalone component used inside the TreeTable, refer to the paginator for more information about the accessibility features.

Sortable Headers Keyboard Support

KeyFunction
tabMoves through the headers.
enterSorts the column.
spaceSorts the column.

Keyboard Support

KeyFunction
tab Moves focus to the first selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the next focusable element in the page tab sequence.
shift + tab Moves focus to the last selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the previous focusable element in the page tab sequence.
enterSelects the focused treenode.
spaceSelects the focused treenode.
down arrowMoves focus to the next treenode.
up arrowMoves focus to the previous treenode.
right arrowIf node is closed, opens the node otherwise moves focus to the first child node.
left arrowIf node is open, closes the node otherwise moves focus to the parent node.