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 7 layout components for organizing content, creating containers, and building responsive layouts with panels, cards, and dividers.
Content container with optional header, footer, and actions.
// Import
import { Card } from 'primeng/card';
// Module: CardModule
// Component Interface
interface CardProps {
header?: string;
subheader?: string;
style?: any;
styleClass?: string;
}
// Usage
@Component({
template: `
<!-- Basic Card -->
<p-card header="Simple Card" subheader="Card subtitle" [style]="{width: '360px'}">
<ng-template pTemplate="header">
<img alt="Card" src="assets/showcase/images/usercard.png" />
</ng-template>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<ng-template pTemplate="footer">
<p-button label="Save" icon="pi pi-check"></p-button>
<p-button label="Cancel" severity="secondary" icon="pi pi-times" [style]="{'margin-left': '.5em'}"></p-button>
</ng-template>
</p-card>
<!-- Advanced Card with Custom Templates -->
<p-card styleClass="p-card-shadow">
<ng-template pTemplate="header">
<div class="flex align-items-center justify-content-between mb-0">
<div class="flex align-items-center gap-2">
<p-avatar image="assets/showcase/images/demo/avatar/walter.jpg" size="large" shape="circle"></p-avatar>
<div>
<div class="font-medium text-xl text-900">Walter White</div>
<div class="font-medium text-sm text-700">@walterwhite</div>
</div>
</div>
<p-button icon="pi pi-ellipsis-v" [text]="true" [rounded]="true" severity="secondary"></p-button>
</div>
</ng-template>
<div class="font-medium text-900 mb-2">What's everyone up to today?</div>
<p class="line-height-3 m-0 mb-3 text-700">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam.
</p>
<img class="w-full" src="assets/showcase/images/demo/nature/nature4.jpg" alt="nature4">
<ng-template pTemplate="footer">
<div class="flex gap-3 mt-3">
<p-button icon="pi pi-heart" [outlined]="true" severity="help"></p-button>
<p-button icon="pi pi-comment" [outlined]="true"></p-button>
<p-button icon="pi pi-share-alt" [outlined]="true"></p-button>
</div>
</ng-template>
</p-card>
`
})Collapsible content panel with toggle functionality.
// Import
import { Panel } from 'primeng/panel';
// Module: PanelModule
// Component Interface
interface PanelProps {
header?: string;
toggleable?: boolean;
collapsed?: boolean;
style?: any;
styleClass?: string;
expandIcon?: string;
collapseIcon?: string;
showHeader?: boolean;
toggler?: 'icon' | 'header';
transitionOptions?: string;
}
// Events
interface PanelBeforeToggleEvent {
originalEvent: Event;
collapsed: boolean;
}
interface PanelAfterToggleEvent {
originalEvent: Event;
collapsed: boolean;
}
// Usage
@Component({
template: `
<!-- Basic Panel -->
<p-panel header="Header" [toggleable]="true">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p-panel>
<!-- Panel with Custom Header -->
<p-panel [toggleable]="true" (onBeforeToggle)="beforeToggle($event)" (onAfterToggle)="afterToggle($event)">
<ng-template pTemplate="header">
<div class="flex align-items-center gap-2">
<p-avatar image="assets/showcase/images/demo/avatar/amyelsner.png" size="large" shape="circle"></p-avatar>
<span class="font-bold">Amy Elsner</span>
</div>
</ng-template>
<ng-template pTemplate="icons">
<button pButton class="p-panel-header-icon p-link" (click)="saveState()">
<span class="pi pi-cog"></span>
</button>
<p-menu #menu [popup]="true" [model]="items"></p-menu>
<button pButton class="p-panel-header-icon p-link" (click)="menu.toggle($event)">
<span class="pi pi-ellipsis-v"></span>
</button>
</ng-template>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</p-panel>
`
})
export class PanelComponent {
items: MenuItem[] = [
{ label: 'Update', icon: 'pi pi-refresh' },
{ label: 'Delete', icon: 'pi pi-times' }
];
beforeToggle(event: PanelBeforeToggleEvent) {
console.log('Before toggle:', event.collapsed);
}
afterToggle(event: PanelAfterToggleEvent) {
console.log('After toggle:', event.collapsed);
}
saveState() {
console.log('State saved');
}
}Grouped form fields with legend and optional toggle.
// Import
import { Fieldset } from 'primeng/fieldset';
// Module: FieldsetModule
// Component Interface
interface FieldsetProps {
legend?: string;
toggleable?: boolean;
collapsed?: boolean;
style?: any;
styleClass?: string;
transitionOptions?: string;
expandIcon?: string;
collapseIcon?: string;
toggler?: 'icon' | 'header';
}
// Events
interface FieldsetBeforeToggleEvent {
originalEvent: Event;
collapsed: boolean;
}
interface FieldsetAfterToggleEvent {
originalEvent: Event;
collapsed: boolean;
}
// Usage
@Component({
template: `
<!-- Basic Fieldset -->
<p-fieldset legend="Header" [toggleable]="true">
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</p-fieldset>
<!-- Fieldset with Custom Legend -->
<p-fieldset [toggleable]="true" (onBeforeToggle)="beforeToggle($event)" (onAfterToggle)="afterToggle($event)">
<ng-template pTemplate="legend">
<div class="flex align-items-center pl-2">
<p-avatar image="assets/showcase/images/demo/avatar/amyelsner.png" size="large" shape="circle"></p-avatar>
<span class="font-bold">Amy Elsner</span>
</div>
</ng-template>
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</p>
</p-fieldset>
<!-- Form Fieldset -->
<p-fieldset legend="Personal Information">
<div class="p-fluid formgrid grid">
<div class="field col-12 md:col-6">
<label for="firstname">Firstname</label>
<input pInputText id="firstname" type="text" />
</div>
<div class="field col-12 md:col-6">
<label for="lastname">Lastname</label>
<input pInputText id="lastname" type="text" />
</div>
<div class="field col-12">
<label for="address">Address</label>
<textarea pInputTextarea id="address" rows="4"></textarea>
</div>
</div>
</p-fieldset>
`
})
export class FieldsetComponent {
beforeToggle(event: FieldsetBeforeToggleEvent) {
console.log('Before toggle:', event.collapsed);
}
afterToggle(event: FieldsetAfterToggleEvent) {
console.log('After toggle:', event.collapsed);
}
}Content separator with text and alignment options.
// Import
import { Divider } from 'primeng/divider';
// Module: DividerModule
// Component Interface
interface DividerProps {
align?: 'left' | 'center' | 'right' | 'top' | 'center' | 'bottom';
layout?: 'horizontal' | 'vertical';
type?: 'solid' | 'dashed' | 'dotted';
style?: any;
styleClass?: string;
}
// Usage
@Component({
template: `
<!-- Basic Horizontal Divider -->
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p-divider></p-divider>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
<!-- Divider with Text -->
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p-divider align="center" type="dashed">
<b>OR</b>
</p-divider>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
<!-- Divider with Icon -->
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p-divider align="left">
<div class="inline-flex align-items-center">
<i class="pi pi-user mr-2"></i>
<b>Icon</b>
</div>
</p-divider>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
<!-- Vertical Divider -->
<div class="flex">
<div class="flex align-items-center justify-content-center w-full">
Box 1
</div>
<p-divider layout="vertical"></p-divider>
<div class="flex align-items-center justify-content-center w-full">
Box 2
</div>
<p-divider layout="vertical">
<i class="pi pi-search"></i>
</p-divider>
<div class="flex align-items-center justify-content-center w-full">
Box 3
</div>
</div>
`
})Action toolbar container for buttons and controls.
// Import
import { Toolbar } from 'primeng/toolbar';
// Module: ToolbarModule
// Component Interface
interface ToolbarProps {
style?: any;
styleClass?: string;
ariaLabelledBy?: string;
}
// Usage
@Component({
template: `
<!-- Basic Toolbar -->
<p-toolbar>
<ng-template pTemplate="start">
<p-button label="New" icon="pi pi-plus" severity="success" class="mr-2"></p-button>
<p-button label="Upload" icon="pi pi-upload" severity="info"></p-button>
</ng-template>
<ng-template pTemplate="center">
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<input pInputText placeholder="Search" />
</span>
</ng-template>
<ng-template pTemplate="end">
<p-splitbutton label="Save" icon="pi pi-check" [model]="items" severity="warning"></p-splitbutton>
</ng-template>
</p-toolbar>
<!-- Custom Toolbar -->
<p-toolbar styleClass="mb-4 gap-2">
<ng-template pTemplate="start">
<p-button severity="success" label="New" icon="pi pi-plus" class="mr-2"></p-button>
<p-button severity="info" label="Upload" icon="pi pi-upload"></p-button>
<i class="pi pi-bars p-toolbar-separator mr-2" style="vertical-align: middle"></i>
<p-button label="Print" icon="pi pi-print" class="p-button-text"></p-button>
<p-button label="Export" icon="pi pi-file-excel" class="p-button-text p-button-success"></p-button>
</ng-template>
<ng-template pTemplate="end">
<p-button icon="pi pi-search" class="mr-2"></p-button>
<p-button icon="pi pi-calendar" severity="success" class="mr-2"></p-button>
<p-button icon="pi pi-times" severity="danger"></p-button>
</ng-template>
</p-toolbar>
`
})
export class ToolbarComponent implements OnInit {
items: MenuItem[] = [];
ngOnInit() {
this.items = [
{
label: 'Update',
icon: 'pi pi-refresh'
},
{
label: 'Delete',
icon: 'pi pi-times'
}
];
}
}Custom scrollable area with styled scrollbars.
// Import
import { ScrollPanel } from 'primeng/scrollpanel';
// Module: ScrollPanelModule
// Component Interface
interface ScrollPanelProps {
style?: any;
styleClass?: string;
step?: number;
}
// Usage
@Component({
template: `
<!-- Basic ScrollPanel -->
<p-scrollpanel [style]="{width: '100%', height: '200px'}">
<div style="padding:1em;line-height:1.5">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam,
eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam
voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</div>
</p-scrollpanel>
<!-- Custom Styled ScrollPanel -->
<p-scrollpanel [style]="{width: '100%', height: '200px'}" styleClass="custombar1">
<div style="padding: 1em; line-height: 1.5; width: 600px;">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam,
eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam
voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</div>
</p-scrollpanel>
<!-- ScrollPanel with Table -->
<p-scrollpanel [style]="{width: '100%', height: '200px'}">
<p-table [value]="customers" [scrollable]="true" scrollHeight="200px">
<ng-template pTemplate="header">
<tr>
<th>Name</th>
<th>Country</th>
<th>Company</th>
<th>Representative</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-customer>
<tr>
<td>{{customer.name}}</td>
<td>{{customer.country.name}}</td>
<td>{{customer.company}}</td>
<td>{{customer.representative.name}}</td>
</tr>
</ng-template>
</p-table>
</p-scrollpanel>
`
})Resizable layout splitter for creating adjustable panels.
// Import
import { Splitter, SplitterPanel } from 'primeng/splitter';
// Module: SplitterModule
// Component Interface
interface SplitterProps {
style?: any;
styleClass?: string;
panelSizes?: number[];
minSizes?: number[];
layout?: 'horizontal' | 'vertical';
gutterSize?: number;
stateKey?: string;
stateStorage?: 'local' | 'session';
step?: number;
}
interface SplitterPanelProps {
size?: number;
minSize?: number;
style?: any;
styleClass?: string;
}
// Events
interface SplitterResizeEndEvent {
originalEvent: Event;
sizes: number[];
}
interface SplitterResizeStartEvent {
originalEvent: Event;
sizes: number[];
}
// Usage
@Component({
template: `
<!-- Horizontal Splitter -->
<p-splitter [style]="{height: '300px'}" styleClass="mb-5" (onResizeEnd)="onResize($event)">
<ng-template pTemplate>
<div class="col flex align-items-center justify-content-center">
Panel 1
</div>
</ng-template>
<ng-template pTemplate>
<div class="col flex align-items-center justify-content-center">
Panel 2
</div>
</ng-template>
</p-splitter>
<!-- Vertical Splitter -->
<p-splitter layout="vertical" [style]="{height: '300px'}" styleClass="mb-5">
<ng-template pTemplate>
<div class="col flex align-items-center justify-content-center">
Panel 1
</div>
</ng-template>
<ng-template pTemplate>
<div class="col flex align-items-center justify-content-center">
Panel 2
</div>
</ng-template>
</p-splitter>
<!-- Nested Splitters -->
<p-splitter [style]="{height: '300px'}" [panelSizes]="[20, 80]" [minSizes]="[10, 0]" styleClass="mb-5">
<ng-template pTemplate>
<div class="col flex align-items-center justify-content-center">
Panel 1
</div>
</ng-template>
<ng-template pTemplate>
<p-splitter layout="vertical" [panelSizes]="[15, 85]">
<ng-template pTemplate>
<div style="flex-grow: 1;" class="flex align-items-center justify-content-center">
Panel 2
</div>
</ng-template>
<ng-template pTemplate>
<div style="flex-grow: 1;" class="flex align-items-center justify-content-center">
Panel 3
</div>
</ng-template>
</p-splitter>
</ng-template>
</p-splitter>
<!-- Splitter with SplitterPanel Components -->
<p-splitter [style]="{height: '300px'}">
<p-splitterpanel [size]="30" [minSize]="10">
<div class="col flex align-items-center justify-content-center">
Panel 1
</div>
</p-splitterpanel>
<p-splitterpanel [size]="70">
<div class="col flex align-items-center justify-content-center">
Panel 2
</div>
</p-splitterpanel>
</p-splitter>
`
})
export class SplitterComponent {
onResize(event: SplitterResizeEndEvent) {
console.log('Splitter resized:', event.sizes);
}
}PrimeNG layout components work seamlessly with CSS Grid and Flexbox for responsive designs:
@Component({
template: `
<!-- Responsive Card Layout -->
<div class="grid">
<div class="col-12 md:col-6 lg:col-4" *ngFor="let product of products">
<p-card [style]="{height: '100%'}">
<ng-template pTemplate="header">
<img [src]="product.image" [alt]="product.name" class="w-full">
</ng-template>
<div class="text-2xl font-bold mb-2">{{product.name}}</div>
<p class="text-color-secondary line-height-3">{{product.description}}</p>
<ng-template pTemplate="footer">
<div class="flex gap-2">
<p-button label="Buy Now" class="flex-auto"></p-button>
<p-button icon="pi pi-heart" severity="secondary" [outlined]="true"></p-button>
</div>
</ng-template>
</p-card>
</div>
</div>
<!-- Responsive Panel Layout -->
<div class="grid">
<div class="col-12 lg:col-8">
<p-panel header="Main Content" [toggleable]="true">
<p>Main content goes here...</p>
</p-panel>
</div>
<div class="col-12 lg:col-4">
<p-panel header="Sidebar" [toggleable]="true">
<p>Sidebar content goes here...</p>
</p-panel>
</div>
</div>
<!-- Responsive Toolbar -->
<p-toolbar styleClass="mb-4">
<ng-template pTemplate="start">
<div class="flex flex-column md:flex-row gap-2">
<p-button label="New" icon="pi pi-plus" size="small" class="md:mr-2"></p-button>
<p-button label="Upload" icon="pi pi-upload" size="small"></p-button>
</div>
</ng-template>
<ng-template pTemplate="center">
<div class="hidden md:block">
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<input pInputText placeholder="Search" />
</span>
</div>
</ng-template>
<ng-template pTemplate="end">
<p-button icon="pi pi-cog" [text]="true" severity="secondary"></p-button>
</ng-template>
</p-toolbar>
`
})
export class ResponsiveLayoutComponent {
products = [
{ name: 'Product 1', image: 'assets/product1.jpg', description: 'Description 1' },
{ name: 'Product 2', image: 'assets/product2.jpg', description: 'Description 2' }
];
}All layout components automatically adapt to dark themes:
// Custom dark theme overrides
.p-dark {
.p-card {
background: var(--surface-card);
border: 1px solid var(--surface-border);
}
.p-panel .p-panel-header {
background: var(--surface-section);
border-color: var(--surface-border);
}
.p-toolbar {
background: var(--surface-section);
border-color: var(--surface-border);
}
}Layout components integrate well with popular CSS frameworks:
<!-- Bootstrap Integration -->
<div class="container">
<div class="row">
<div class="col-md-8">
<p-card header="Main Content"></p-card>
</div>
<div class="col-md-4">
<p-panel header="Sidebar"></p-panel>
</div>
</div>
</div>
<!-- Tailwind CSS Integration -->
<div class="container mx-auto px-4">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<p-card class="shadow-lg"></p-card>
<p-card class="shadow-lg"></p-card>
<p-card class="shadow-lg"></p-card>
</div>
</div>Install with Tessl CLI
npx tessl i tessl/npm-primeng