Comprehensive Angular UI component library with 80+ components for building modern web applications
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
PrimeNG provides 11 powerful components for displaying and organizing data, from simple lists to complex interactive tables and visualizations.
Advanced data table with sorting, filtering, pagination, and selection.
// Import
import { Table } from 'primeng/table';
// Module: TableModule
// Component Interface
interface TableProps {
value?: any[];
columns?: any[];
paginator?: boolean;
rows?: number;
first?: number;
pageLinks?: number;
rowsPerPageOptions?: number[];
alwaysShowPaginator?: boolean;
paginatorPosition?: 'top' | 'bottom' | 'both';
paginatorDropdownAppendTo?: any;
currentPageReportTemplate?: string;
showCurrentPageReport?: boolean;
showJumpToPageDropdown?: boolean;
showFirstLastIcon?: boolean;
showPageLinks?: boolean;
defaultSortOrder?: number;
sortMode?: 'single' | 'multiple';
sortField?: string;
sortOrder?: number;
multiSortMeta?: SortMeta[];
selection?: any;
selectionMode?: 'single' | 'multiple';
compareSelectionBy?: string;
dataKey?: string;
metaKeySelection?: boolean;
rowTrackBy?: Function;
lazy?: boolean;
lazyLoadOnInit?: boolean;
csvSeparator?: string;
exportFilename?: string;
filters?: { [key: string]: FilterMetadata };
globalFilterFields?: string[];
filterDelay?: number;
filterLocale?: string;
expandedRowKeys?: { [key: string]: boolean };
editMode?: 'cell' | 'row';
editingRowKeys?: { [key: string]: boolean };
rowGroupMode?: 'subheader' | 'rowspan';
groupRowsBy?: string;
expandableRowGroups?: boolean;
expandedRowGroups?: any[];
scrollable?: boolean;
scrollDirection?: string;
scrollHeight?: string;
virtualScroll?: boolean;
virtualScrollItemSize?: number;
virtualScrollOptions?: ScrollerOptions;
frozenColumns?: any[];
frozenValue?: any[];
resizableColumns?: boolean;
columnResizeMode?: string;
reorderableColumns?: boolean;
loading?: boolean;
loadingIcon?: string;
rowHover?: boolean;
customSort?: boolean;
showLoader?: boolean;
responsiveLayout?: string;
breakpoint?: string;
tableStyle?: any;
tableStyleClass?: string;
rowClass?: string;
rowStyle?: any;
rowData?: any;
rowIndex?: number;
}
// Events
interface TableRowSelectEvent {
originalEvent: Event;
data: any;
type: 'row' | 'radiobutton' | 'checkbox';
index: number;
}
interface TableRowUnSelectEvent {
originalEvent: Event;
data: any;
type: 'row' | 'radiobutton' | 'checkbox';
index: number;
}
interface TableSelectAllChangeEvent {
originalEvent: Event;
checked: boolean;
}
interface TableRowEditInitEvent {
originalEvent: Event;
data: any;
field: string;
index: number;
}
interface TableRowEditSaveEvent {
originalEvent: Event;
data: any;
field: string;
index: number;
}
interface TableRowEditCancelEvent {
originalEvent: Event;
data: any;
field: string;
index: number;
}
interface TableSortEvent {
originalEvent: Event;
data?: any[];
mode?: string;
field?: string;
order?: number;
multiSortMeta?: SortMeta[];
}
interface TableFilterEvent {
originalEvent: Event;
filters: { [key: string]: FilterMetadata };
filteredValue?: any[];
}
interface TablePageEvent {
originalEvent: Event;
first: number;
rows: number;
page: number;
pageCount: number;
}
// Usage Example
@Component({
template: `
<p-table
[value]="products"
[paginator]="true"
[rows]="10"
[showCurrentPageReport]="true"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"
[rowsPerPageOptions]="[10,25,50]"
dataKey="id"
[rowHover]="true"
[loading]="loading"
[globalFilterFields]="['name','country.name','representative.name','status']"
(onRowSelect)="onRowSelect($event)"
(onRowUnselect)="onRowUnselect($event)">
<ng-template pTemplate="caption">
<div class="flex">
<button pButton label="Clear" class="p-button-outlined" icon="pi pi-filter-slash" (click)="clear(table)"></button>
<span class="p-input-icon-left ml-auto">
<i class="pi pi-search"></i>
<input pInputText type="text" (input)="table.filterGlobal($event.target.value, 'contains')" placeholder="Search keyword" />
</span>
</div>
</ng-template>
<ng-template pTemplate="header">
<tr>
<th style="width: 3rem">
<p-tableHeaderCheckbox></p-tableHeaderCheckbox>
</th>
<th pSortableColumn="name">Name <p-sortIcon field="name"></p-sortIcon></th>
<th pSortableColumn="country.name">Country <p-sortIcon field="country.name"></p-sortIcon></th>
<th pSortableColumn="representative.name">Agent <p-sortIcon field="representative.name"></p-sortIcon></th>
<th pSortableColumn="status">Status <p-sortIcon field="status"></p-sortIcon></th>
<th pSortableColumn="activity">Activity <p-sortIcon field="activity"></p-sortIcon></th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-product let-rowIndex="rowIndex">
<tr [pSelectableRow]="product" [pSelectableRowIndex]="rowIndex">
<td>
<p-tableCheckbox [value]="product"></p-tableCheckbox>
</td>
<td>{{product.name}}</td>
<td>
<img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + product.country.code" style="width: 20px">
<span class="ml-1 vertical-align-middle">{{product.country.name}}</span>
</td>
<td>
<img [alt]="product.representative.name" src="assets/showcase/images/demo/avatar/{{product.representative.image}}" width="32" style="vertical-align: middle" />
<span class="ml-1 vertical-align-middle">{{product.representative.name}}</span>
</td>
<td>
<span [class]="'customer-badge status-' + product.status">{{product.status}}</span>
</td>
<td>
<p-progressbar [value]="product.activity" [showValue]="false"></p-progressbar>
</td>
</tr>
</ng-template>
</p-table>
`
})
export class TableComponent {
products: Product[] = [];
selectedProducts: Product[] = [];
loading: boolean = false;
onRowSelect(event: TableRowSelectEvent) {
// Handle row selection
}
}Hierarchical data table with tree structure.
// Import
import { TreeTable } from 'primeng/treetable';
// Module: TreeTableModule
// Component Interface
interface TreeTableProps {
value?: TreeNode[];
columns?: any[];
selection?: any;
selectionMode?: 'single' | 'multiple' | 'checkbox';
dataKey?: string;
compareSelectionBy?: string;
metaKeySelection?: boolean;
rows?: number;
first?: number;
paginator?: boolean;
pageLinks?: number;
rowsPerPageOptions?: number[];
alwaysShowPaginator?: boolean;
paginatorPosition?: 'top' | 'bottom' | 'both';
sortMode?: 'single' | 'multiple';
sortField?: string;
sortOrder?: number;
multiSortMeta?: SortMeta[];
customSort?: boolean;
scrollable?: boolean;
scrollDirection?: string;
scrollHeight?: string;
frozenWidth?: string;
frozenColumns?: any[];
resizableColumns?: boolean;
columnResizeMode?: string;
reorderableColumns?: boolean;
loading?: boolean;
loadingIcon?: string;
rowHover?: boolean;
trackBy?: Function;
filters?: { [key: string]: FilterMetadata };
globalFilterFields?: string[];
filterDelay?: number;
filterMode?: string;
filterLocale?: string;
tableStyle?: any;
tableStyleClass?: string;
}
// Usage
@Component({
template: `
<p-treetable [value]="files" [columns]="cols" selectionMode="checkbox" [(selection)]="selectedFiles">
<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 [ttSelectableRow]="rowNode">
<td *ngFor="let col of columns; let i = index">
<p-treeTableToggler [rowNode]="rowNode" *ngIf="i == 0"></p-treeTableToggler>
<p-treeTableCheckbox [value]="rowNode" *ngIf="i == 0"></p-treeTableCheckbox>
{{rowData[col.field]}}
</td>
</tr>
</ng-template>
</p-treetable>
`
})Flexible data presentation with list and grid layouts.
// Import
import { DataView } from 'primeng/dataview';
// Module: DataViewModule
// Component Interface
interface DataViewProps {
value?: any[];
layout?: 'list' | 'grid';
paginator?: boolean;
rows?: number;
first?: number;
totalRecords?: number;
pageLinks?: number;
rowsPerPageOptions?: number[];
paginatorPosition?: 'top' | 'bottom' | 'both';
alwaysShowPaginator?: boolean;
paginatorDropdownAppendTo?: any;
currentPageReportTemplate?: string;
showCurrentPageReport?: boolean;
showJumpToPageDropdown?: boolean;
showFirstLastIcon?: boolean;
showPageLinks?: boolean;
lazy?: boolean;
emptyMessage?: string;
trackBy?: Function;
filterBy?: string;
filterLocale?: string;
loading?: boolean;
loadingIcon?: string;
sortField?: string;
sortOrder?: number;
}
// Usage
@Component({
template: `
<p-dataview
[value]="products"
[paginator]="true"
[rows]="9"
filterBy="name"
[sortField]="sortField"
[sortOrder]="sortOrder"
layout="grid">
<ng-template pTemplate="header">
<div class="flex flex-column md:flex-row md:justify-content-between">
<span class="p-input-icon-left mb-2 md:mb-0">
<i class="pi pi-search"></i>
<input type="search" pInputText placeholder="Search by Name" (input)="filter($event)" />
</span>
<p-dataviewlayoutoptions></p-dataviewlayoutoptions>
</div>
</ng-template>
<ng-template let-product pTemplate="listItem">
<div class="col-12">
<div class="flex flex-column xl:flex-row xl:align-items-start p-4 gap-4">
<img class="w-9 sm:w-16rem xl:w-10rem shadow-2 block xl:block mx-auto border-round" [src]="'assets/showcase/images/demo/product/' + product.image" [alt]="product.name" />
<div class="flex flex-column sm:flex-row justify-content-between align-items-center xl:align-items-start flex-1 gap-4">
<div class="flex flex-column align-items-center sm:align-items-start gap-3">
<div class="text-2xl font-bold text-900">{{product.name}}</div>
<p-rating [ngModel]="product.rating" [readonly]="true" [cancel]="false"></p-rating>
<div class="flex align-items-center gap-3">
<span class="flex align-items-center gap-2">
<i class="pi pi-tag"></i>
<span class="font-semibold">{{product.category}}</span>
</span>
<p-tag [value]="product.inventoryStatus" [severity]="getSeverity(product)"></p-tag>
</div>
</div>
<div class="flex sm:flex-column align-items-center sm:align-items-end gap-3 sm:gap-2">
<span class="text-2xl font-semibold">${{product.price}}</span>
<button pButton pRipple [disabled]="product.inventoryStatus === 'OUTOFSTOCK'" class="p-button-rounded" icon="pi pi-shopping-cart"></button>
</div>
</div>
</div>
</div>
</ng-template>
<ng-template let-product pTemplate="gridItem">
<div class="col-12 sm:col-6 lg:col-12 xl:col-4 p-2">
<div class="p-4 border-1 surface-border surface-card border-round">
<div class="flex flex-wrap align-items-center justify-content-between gap-2">
<div class="flex align-items-center gap-2">
<i class="pi pi-tag"></i>
<span class="font-semibold">{{product.category}}</span>
</div>
<p-tag [value]="product.inventoryStatus" [severity]="getSeverity(product)"></p-tag>
</div>
<div class="flex flex-column align-items-center gap-3 py-5">
<img class="w-9 shadow-2 border-round" [src]="'assets/showcase/images/demo/product/' + product.image" [alt]="product.name" />
<div class="text-2xl font-bold">{{product.name}}</div>
<p-rating [ngModel]="product.rating" [readonly]="true" [cancel]="false"></p-rating>
</div>
<div class="flex align-items-center justify-content-between">
<span class="text-2xl font-semibold">${{product.price}}</span>
<button pButton pRipple [disabled]="product.inventoryStatus === 'OUTOFSTOCK'" class="p-button-rounded" icon="pi pi-shopping-cart"></button>
</div>
</div>
</div>
</ng-template>
</p-dataview>
`
})Hierarchical tree structure display.
// Import
import { Tree } from 'primeng/tree';
// Module: TreeModule
// Component Interface
interface TreeProps {
value?: TreeNode[];
selectionMode?: 'single' | 'multiple' | 'checkbox';
selection?: any;
loading?: boolean;
loadingIcon?: string;
emptyMessage?: string;
ariaLabel?: string;
togglerAriaLabel?: string;
ariaLabelledBy?: string;
validateDrop?: boolean;
filter?: boolean;
filterBy?: string;
filterMode?: string;
filterPlaceholder?: string;
filteredNodes?: TreeNode[];
filterLocale?: string;
scrollHeight?: string;
virtualScroll?: boolean;
virtualNodeHeight?: number;
minBufferPx?: number;
maxBufferPx?: number;
indentation?: number;
layout?: string;
draggableScope?: any;
droppableScope?: any;
draggableNodes?: boolean;
droppableNodes?: boolean;
metaKeySelection?: boolean;
propagateSelectionUp?: boolean;
propagateSelectionDown?: boolean;
trackBy?: Function;
}
// Events
interface TreeNodeSelectEvent {
originalEvent: Event;
node: TreeNode;
}
interface TreeNodeUnSelectEvent {
originalEvent: Event;
node: TreeNode;
}
interface TreeNodeExpandEvent {
originalEvent: Event;
node: TreeNode;
}
interface TreeNodeCollapseEvent {
originalEvent: Event;
node: TreeNode;
}
interface TreeNodeDropEvent {
originalEvent: Event;
node: TreeNode;
subNodes: TreeNode[];
index: number;
scope: any;
}
// Usage
@Component({
template: `
<p-tree
[value]="files"
selectionMode="multiple"
[(selection)]="selectedFiles"
[filter]="true"
filterPlaceholder="Search files"
(onNodeSelect)="onNodeSelect($event)"
(onNodeUnselect)="onNodeUnselect($event)">
<ng-template let-node pTemplate="default">
<span>{{node.label}}</span>
</ng-template>
</p-tree>
`
})Image gallery with thumbnails and navigation.
// Import
import { Galleria } from 'primeng/galleria';
// Module: GalleriaModule
// Component Interface
interface GalleriaProps {
value?: any[];
activeIndex?: number;
fullScreen?: boolean;
id?: string;
item?: any;
circular?: boolean;
showItemNavigators?: boolean;
showIndicators?: boolean;
slideShowActive?: boolean;
changeItemOnIndicatorHover?: boolean;
autoPlay?: boolean;
transitionInterval?: number;
showThumbnails?: boolean;
thumbnailsPosition?: string;
verticalThumbnailViewPortHeight?: number;
showItemNavigatorsOnHover?: boolean;
showIndicatorsOnItem?: boolean;
indicatorsPosition?: string;
baseZIndex?: number;
maskClass?: string;
containerClass?: string;
containerStyle?: any;
showTransitionOptions?: string;
hideTransitionOptions?: string;
}
// Usage
@Component({
template: `
<p-galleria
[(value)]="images"
[responsiveOptions]="responsiveOptions"
[containerStyle]="{'max-width': '640px'}"
[numVisible]="5"
[circular]="true"
[fullScreen]="true"
[showItemNavigators]="true"
[showThumbnails]="false">
<ng-template pTemplate="item" let-item>
<img [src]="item.previewImageSrc" [alt]="item.alt" style="width: 100%; display: block;" />
</ng-template>
<ng-template pTemplate="thumbnail" let-item>
<div class="grid grid-nogutter justify-content-center">
<img [src]="item.thumbnailImageSrc" [alt]="item.alt" style="display: block;" />
</div>
</ng-template>
</p-galleria>
`
})Content carousel with navigation and indicators.
// Import
import { Carousel } from 'primeng/carousel';
// Module: CarouselModule
// Component Interface
interface CarouselProps {
value?: any[];
page?: number;
numVisible?: number;
numScroll?: number;
responsiveOptions?: CarouselResponsiveOption[];
orientation?: 'horizontal' | 'vertical';
verticalViewPortHeight?: string;
contentClass?: string;
indicatorsContentClass?: string;
circular?: boolean;
showIndicators?: boolean;
showNavigators?: boolean;
autoplayInterval?: number;
}
interface CarouselResponsiveOption {
breakpoint: string;
numVisible: number;
numScroll: number;
}
// Usage
@Component({
template: `
<p-carousel
[value]="products"
[numVisible]="3"
[numScroll]="1"
[circular]="true"
[autoplayInterval]="3000"
[responsiveOptions]="responsiveOptions">
<ng-template pTemplate="item" let-product>
<div class="border-1 surface-border border-round m-2 text-center py-5 px-3">
<div class="mb-3">
<img src="assets/showcase/images/demo/product/{{product.image}}" [alt]="product.name" class="w-6 shadow-2" />
</div>
<div>
<h4 class="mb-1">{{product.name}}</h4>
<h6 class="mt-0 mb-3">${{product.price}}</h6>
<p-tag [value]="product.inventoryStatus" [severity]="getSeverity(product)"></p-tag>
<div class="mt-5 flex flex-wrap gap-2 justify-content-center">
<button pButton type="button" class="p-button-rounded" icon="pi pi-search"></button>
<button pButton type="button" class="p-button-rounded p-button-success" icon="pi pi-star-fill"></button>
</div>
</div>
</div>
</ng-template>
</p-carousel>
`
})Enhanced image display with preview and zoom.
// Import
import { Image } from 'primeng/image';
// Module: ImageModule
// Component Interface
interface ImageProps {
imageClass?: string;
imageStyle?: any;
src?: string;
alt?: string;
width?: string;
height?: string;
appendTo?: any;
preview?: boolean;
showTransitionOptions?: string;
hideTransitionOptions?: string;
closeOnEscape?: boolean;
}
// Usage
@Component({
template: `
<p-image
src="assets/showcase/images/demo/galleria/galleria1.jpg"
alt="Image"
width="250"
[preview]="true">
</p-image>
`
})Chronological event display with custom templates.
// Import
import { Timeline } from 'primeng/timeline';
// Module: TimelineModule
// Component Interface
interface TimelineProps {
value?: any[];
layout?: 'vertical' | 'horizontal';
align?: 'left' | 'right' | 'alternate' | 'top' | 'bottom';
styleClass?: string;
style?: any;
}
// Usage
@Component({
template: `
<p-timeline
[value]="events"
align="alternate"
styleClass="customized-timeline">
<ng-template pTemplate="marker" let-event>
<span class="custom-marker shadow-2" [style.backgroundColor]="event.color">
<i [ngClass]="event.icon"></i>
</span>
</ng-template>
<ng-template pTemplate="content" let-event>
<p-card [header]="event.status" [subheader]="event.date">
<img *ngIf="event.image" [src]="'assets/showcase/images/demo/product/' + event.image" [alt]="event.name" width="200" class="shadow-2" />
<p>{{event.description}}</p>
<button pButton pRipple label="Read more" class="p-button-text"></button>
</p-card>
</ng-template>
</p-timeline>
`
})Hierarchical organization structure display.
// Import
import { OrganizationChart } from 'primeng/organizationchart';
// Module: OrganizationChartModule
// Component Interface
interface OrganizationChartProps {
value?: TreeNode[];
style?: any;
styleClass?: string;
selectionMode?: 'single' | 'multiple';
selection?: any;
preserveSpace?: boolean;
}
// Usage
@Component({
template: `
<p-organizationchart
[value]="data"
selectionMode="single"
[(selection)]="selectedNode">
<ng-template let-node pTemplate="person">
<div class="node-header ui-corner-top">{{node.label}}</div>
<div class="node-content">
<img src="assets/showcase/images/demo/avatar/{{node.data.avatar}}" width="32">
<div>{{node.data.name}}</div>
</div>
</ng-template>
</p-organizationchart>
`
})Label/badge component for status display.
// Import
import { Tag } from 'primeng/tag';
// Module: TagModule
// Component Interface
interface TagProps {
value?: string;
severity?: 'success' | 'secondary' | 'info' | 'warning' | 'danger' | 'contrast';
rounded?: boolean;
icon?: string;
styleClass?: string;
style?: any;
}
// Usage
@Component({
template: `
<p-tag value="New" severity="success"></p-tag>
<p-tag value="Pending" severity="warning" icon="pi pi-clock"></p-tag>
<p-tag value="Cancelled" severity="danger" [rounded]="true"></p-tag>
`
})Side-by-side image comparison widget.
// Import
import { ImageCompare } from 'primeng/imagecompare';
// Module: ImageCompareModule
// Component Interface
interface ImageCompareProps {
leftImageSrc?: string;
leftImageAlt?: string;
rightImageSrc?: string;
rightImageAlt?: string;
}
// Usage
@Component({
template: `
<p-imagecompare
leftImageSrc="assets/showcase/images/demo/galleria/galleria1.jpg"
rightImageSrc="assets/showcase/images/demo/galleria/galleria1s.jpg"
leftImageAlt="Left Image"
rightImageAlt="Right Image">
</p-imagecompare>
`
})Many data display components support lazy loading and virtual scrolling for performance with large datasets:
// Lazy Loading Example
export class LazyLoadingComponent {
products: Product[] = [];
totalRecords: number = 0;
loading: boolean = false;
loadProducts(event: LazyLoadEvent) {
this.loading = true;
// Simulate API call
setTimeout(() => {
this.productService.getProducts(event).then(data => {
this.products = data.products;
this.totalRecords = data.totalRecords;
this.loading = false;
});
}, 1000);
}
}
// Template
@Component({
template: `
<p-table
[value]="products"
[lazy]="true"
[loading]="loading"
[totalRecords]="totalRecords"
[paginator]="true"
[rows]="10"
(onLazyLoad)="loadProducts($event)">
</p-table>
`
})Advanced filtering and sorting capabilities:
// Filter Metadata Interface
interface FilterMetadata {
value?: any;
matchMode?: string;
operator?: string;
}
// Filter Match Modes
const FilterMatchMode = {
STARTS_WITH: 'startsWith',
CONTAINS: 'contains',
NOT_CONTAINS: 'notContains',
ENDS_WITH: 'endsWith',
EQUALS: 'equals',
NOT_EQUALS: 'notEquals',
LESS_THAN: 'lt',
LESS_THAN_OR_EQUAL_TO: 'lte',
GREATER_THAN: 'gt',
GREATER_THAN_OR_EQUAL_TO: 'gte',
BETWEEN: 'between',
IN: 'in',
IS: 'is',
IS_NOT: 'isNot',
BEFORE: 'before',
AFTER: 'after',
DATE_IS: 'dateIs',
DATE_IS_NOT: 'dateIsNot',
DATE_BEFORE: 'dateBefore',
DATE_AFTER: 'dateAfter'
};
// Sort Meta Interface
interface SortMeta {
field: string;
order: number;
}Install with Tessl CLI
npx tessl i tessl/npm-primeng