Build complete business UIs in Java. 153 components for Jakarta EE, Quarkus and Spring Boot – no npm, no REST layer, no second stack.
Your Java developers build the whole app, from the database to the UI. No separate frontend team, no second stack to build, secure and keep up to date.
DataTable, Schedule, TreeTable, FileUpload, Charts and more, with lazy loading, filtering and export built in.
One Maven dependency. No node_modules, no lockfile churn, no second toolchain to keep patched.
Components bind straight to CDI beans. No REST endpoints, JSON mapping or CORS rules just to talk to yourself.
Validation and business rules run in the JVM, next to your data and security. The browser gets rendered HTML, not your domain model.
Strict nonce-based CSP with one context parameter. Faces itself brings CSRF protection and output escaping.
JUnit 5 and Selenium with ready-made page objects for PrimeFaces components. No second test stack in JavaScript.
Aura, Lara, Nora, Metal and Glass, each in light and dark. Change any token at runtime, no build step.
Keyboard navigation, screen reader support, ARIA roles and focus management built into the components.
Jakarta EE servers, Quarkus and Spring Boot, on Mojarra or MyFaces. Your existing runtime, no extra service.
Add PrimeFaces to Jakarta EE, Quarkus or Spring Boot and bind components straight to your beans.
A sortable, filterable, paginated table is a Facelets view and a CDI bean, nothing else:
field alone gives every column sorting and its own filter.
| PrimeFaces | Angular + component library | |
|---|---|---|
| Files for this table | 2 | 6 |
| Toolchains to build and patch | Maven | Maven, Node, npm, Angular CLI |
| Languages | Java, XHTML | Java, TypeScript, HTML |
| API layer for the UI | None | REST endpoints, DTOs |
Angular files shown next to the code, here with Angular Material as component library. Generated tsconfig.json and index.html, auth token handling and CORS not counted. pom.xml not counted on either side: both projects have one, PrimeFaces adds a single dependency.
Read the Docs<h:form>
<p:dataTable var="c" value="#{customerView.customers}"
paginator="true" rows="10" sortMode="multiple">
<p:column field="name" headerText="Name"/>
<p:column field="country" headerText="Country"/>
<p:column field="status" headerText="Status">
<p:tag value="#{c.status}"/>
</p:column>
</p:dataTable>
</h:form>
import { AfterViewInit, Component, inject, viewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatInputModule } from '@angular/material/input';
import { MatChipsModule } from '@angular/material/chips';
export interface Customer {
name: string;
country: string;
status: string;
}
@Component({
selector: 'app-customers',
imports: [MatTableModule, MatSortModule, MatPaginatorModule, MatInputModule, MatChipsModule],
template: `
<mat-form-field>
<input matInput placeholder="Search" (keyup)="filter($event)">
</mat-form-field>
<table mat-table [dataSource]="customers" matSort>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
<td mat-cell *matCellDef="let c">{{ c.name }}</td>
</ng-container>
<ng-container matColumnDef="country">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Country</th>
<td mat-cell *matCellDef="let c">{{ c.country }}</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Status</th>
<td mat-cell *matCellDef="let c"><mat-chip>{{ c.status }}</mat-chip></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columns"></tr>
<tr mat-row *matRowDef="let row; columns: columns"></tr>
</table>
<mat-paginator [pageSize]="10"></mat-paginator>
`
})
export class CustomersComponent implements AfterViewInit {
private http = inject(HttpClient);
private sort = viewChild.required(MatSort);
private paginator = viewChild.required(MatPaginator);
columns = ['name', 'country', 'status'];
customers = new MatTableDataSource<Customer>();
ngAfterViewInit() {
this.customers.sort = this.sort();
this.customers.paginator = this.paginator();
this.http.get<Customer[]>('/api/customers')
.subscribe(data => this.customers.data = data);
}
filter(event: Event) {
this.customers.filter = (event.target as HTMLInputElement).value.trim().toLowerCase();
}
}
Business applications live for a decade. PrimeFaces has been shipping releases since 2009 and plans for upgrades, not rewrites.
Continuously developed for more than 15 years, with regular major and minor releases.
Every major release documents what changed and how to upgrade.
Free for commercial use, source on GitHub.
Optional support and backports straight from the PrimeFaces project lead.
Join thousands of developers who trust PrimeFaces for their Jakarta Faces applications.