PrimeFaces: Getting Started, Configuration and Themes
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against PrimeFaces 16.0.0 (published 2026-09-04; 15.0.18 is the previous line), Jakarta Faces 4.1 (API
jakarta.faces-api 4.1.2), Eclipse Mojarra 4.1.17 and Apache MyFaces Core 4.1.4, with Java 17 or later for the application.
PrimeFaces itself needs only a Java 11 runtime (its class files are version 55, checked in the 16.0.0 jar) and a Faces 4.0 or
newer implementation: version 16 removed the last javax.* support. Faces 4.0 behaves like 4.1 for everything on this page.
The versions were checked on 2026-10-08.
Everything marked as observed was run in a scratch Bookshelf WAR on Apache Tomcat 11.0.26 (embedded) with Weld 6.0.4.Final, once with Mojarra 4.1.17 and once with MyFaces 4.1.4; the hello-world page and the theme switch were also run on Mojarra 4.0.26. Computed styles, fonts and widths were read with headless Chrome 155. Servers other than Tomcat (WildFly, GlassFish, Payara, Open Liberty, TomEE) were not run for this page. Statements that rest only on the PrimeFaces documentation or on the 16.0.0 source are said so. Data tables, Ajax and forms, dialogs, file upload and charts have their own pages in this section; here they appear only where a setting of this page changes them.
What PrimeFaces Adds to Faces
PrimeFaces is a component library for Faces: tags in the p: namespace (176 tags in the 16.0.0 tag library, from
p:accordionPanel to p:wizard), a theme system, a JavaScript layer built on jQuery that every component talks to, and a
set of replacements for parts of the standard machinery. What the 16.0.0 jar registers on its own (read from its
META-INF/faces-config.xml and web-fragment.xml) is the reason a page with no explicit setup already behaves differently:
| Registration | Effect |
|---|---|
Renderers for |
|
|
Wraps resource handling: PrimeFaces resource URLs carry the parameter |
|
PrimeFaces’s own faces-context and partial-view-context factories, installed through the standard |
Phase listeners |
Named after |
Validators for the ids |
Classes in |
|
Declared in the jar’s |
The PrimeFaces jar also contains a beans.xml with bean-discovery-mode="all", so a CDI container scans it. On a servlet
container that has no Bean Validation or Jakarta Persistence API on the class path, Weld 6.0.4 logged 36 WELD-000119 lines at
INFO level ("Not generating any bean definitions from org.primefaces... because of underlying class loading error: Type
jakarta.validation... not found"). The application worked; the lines only mean that the optional PrimeFaces features
that need those APIs are off (The Dependency and the Optional Libraries).
The Dependency and the Optional Libraries
PrimeFaces is one jar, org.primefaces:primefaces. Its published POM has no compile-scope dependency: mvn dependency:tree on
the project below lists the jar and nothing under it. The libraries PrimeFaces can use are declared provided or
optional, so each one reaches the WAR only if the application asks for it.
<properties>
<maven.compiler.release>21</maven.compiler.release>
<primefaces.version>16.0.0</primefaces.version>
</properties>
<dependencies>
<!-- Faces, CDI and Servlet: provided by the server (see the project setup page for Tomcat) -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>11.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>${primefaces.version}</version>
</dependency>
<!-- every theme except saga-blue; versioned together with PrimeFaces -->
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces-themes</artifactId>
<version>${primefaces.version}</version>
</dependency>
<!-- required by p:textEditor (and by the official hello-world page below) -->
<dependency>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>owasp-java-html-sanitizer</artifactId>
<version>20260101.1</version>
</dependency>
<!-- optional icon font and grid, delivered as WebJars (see the icons and responsive sections) -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>font-awesome</artifactId>
<version>6.7.2</version>
</dependency>
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>primeflex</artifactId>
<version>4.0.0</version>
</dependency>
</dependencies>
The runtime class path of exactly this POM (mvn dependency:copy-dependencies) was primefaces 16.0.0, primefaces-themes 16.0.0,
font-awesome 6.7.2, primeflex 4.0.0 and the sanitizer 20260101.1 with its java8-shim and java10-shim jars. Other server-side
libraries are needed only by one component each. The versions below are the ones the PrimeFaces documentation says were tested
(the 16.0.0 POM leaves the library versions to its parent, so they were not independently checked):
| Library | Coordinates | Tested version | Needed by |
|---|---|---|---|
Bean Validation implementation |
for example Hibernate Validator |
1.1 or later |
the Bean Validation features (see the PrimeFaces Ajax and forms page) |
Apache POI |
|
5.5.1 |
|
OpenPDF |
|
1.4.2 |
|
RSS reader |
|
3.12.0 |
|
Okapi barcode |
|
0.5.2 |
|
OWASP Java HTML Sanitizer |
|
20260101.1 |
|
XDEV Chart.js Java model |
|
2.9.0 |
|
The Faces runtime. The PrimeFaces 16 download page lists Jakarta Faces "4.0 - 5.0" as the supported range, and the migration
guide says the baseline is now Faces 4.0. The dependencies page still says "2.3, 3.0, 4.0" and "Servlet 3.0+"; that table is
stale (flagged). The 16.0.0 jar’s faces-config.xml is a 4.0 document, and the pages of this section ran on Mojarra 4.0.26,
Mojarra 4.1.17 and MyFaces 4.1.4. Faces 5.0 is still a milestone (jakarta.faces-api 5.0.0-M9); the download page already
lists it, but nothing here was run against it.
No server module. On WildFly, GlassFish, Payara, Open Liberty and TomEE the jar travels inside the WAR like any other
dependency. The jar’s web-fragment.xml declares <distributable/>; the deployment and clustering page discusses clustering.
Optional libraries fail loudly. A component whose library is missing does not degrade silently:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="jakarta.faces.html"
xmlns:f="jakarta.faces.core"
xmlns:p="primefaces">
<f:view contentType="text/html;charset=UTF-8" encoding="UTF-8">
<h:head></h:head>
<h:body>
<p:textEditor />
</h:body>
</f:view>
</html>
Without owasp-java-html-sanitizer this page, which is the one in the official guide, answered HTTP 500 on Mojarra and on
MyFaces: "TextEditor component is marked secure='true' but the HTML Sanitizer was not found on the classpath. Either add the HTML
sanitizer to the classpath per the documentation or mark secure='false' if you would like to use the component without the
sanitizer." With the dependency from the POM above it rendered on both. The component sanitises the HTML it receives, because
rich text typed by a user is untrusted markup. The error message offers secure="false"; do not use it for text that other
users will see.
The Namespace and a First Page
The 16.0.0 jar ships two tag libraries for the same components: primefaces.urn.taglib.xml, namespace primefaces, and
primefaces.taglib.xml, namespace http://primefaces.org/ui. Both are discovered automatically and both worked on
Mojarra 4.1.17, MyFaces 4.1.4 and Mojarra 4.0.26. The documentation uses the short form, in line with the jakarta.faces.* URNs
of Faces 4.0 and later; the long form is what every older tutorial and book shows and keeps working.
xmlns:p="primefaces"
xmlns:p="http://primefaces.org/ui"
The smallest page that exercises the theme, the icon font, the component styles and the Ajax script is a form with one input and one button:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="jakarta.faces.html"
xmlns:p="primefaces">
<h:head>
<title>Hello PrimeFaces</title>
</h:head>
<h:body>
<h1>Bookshelf</h1>
<h:form>
<p:inputText placeholder="Search"/>
<p:commandButton value="Go" icon="pi pi-search"/>
</h:form>
</h:body>
</html>
The response head of that page, in the order the markup arrives (Mojarra; identical for MyFaces apart from the client ids), was:
theme.css from the library primefaces-saga-blue, primeicons/primeicons.css, components.css, jquery/jquery.js,
core.js, components.js, jquery/jquery-plugins.js, locales/locale-en.js, then a script that assigns
PrimeFaces.settings. The button rendered <button ... class="ui-button ui-widget ui-state-default ui-button-text-icon-left"
with an ui-icon pi pi-search span. Nothing in the page, in web.xml or in faces-config.xml asked for any of that.
The Head: What PrimeFaces Writes and in Which Order
The h:head of a PrimeFaces application is rendered by org.primefaces.renderkit.HeadRenderer, which replaces the standard
renderer of the type jakarta.faces.Head. Its class comment states the intended order: the first facet, the theme style
sheet, the PrimeIcons style sheet, the middle facet, the registered resources, the client validation scripts, the locale script,
the PrimeFaces.settings script, the initialisation scripts, the content of the h:head element and the last facet. The three
facets are PrimeFaces additions to h:head; the standard element knows no facets.
Reading the response shows how that works in practice, because it differs in one detail from the comment. In the output the theme
and the icon style sheet come with the registered resources and not before the middle facet, so markup in the middle
facet arrives before theme.css. The probe page puts one plain link and one
h:outputStylesheet into each facet and into the head:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="jakarta.faces.core"
xmlns:h="jakarta.faces.html"
xmlns:p="primefaces">
<h:head>
<f:facet name="first">
<link rel="stylesheet" href="#{resource['css:link-first.css']}"/>
<h:outputStylesheet library="css" name="res-first.css"/>
</f:facet>
<title>Resource order</title>
<h:outputStylesheet library="css" name="res-body.css"/>
<link rel="stylesheet" href="#{resource['css:link-body.css']}"/>
<f:facet name="middle">
<link rel="stylesheet" href="#{resource['css:link-middle.css']}"/>
<h:outputStylesheet library="css" name="res-middle.css"/>
</f:facet>
<f:facet name="last">
<link rel="stylesheet" href="#{resource['css:link-last.css']}"/>
<h:outputStylesheet library="css" name="res-last.css"/>
</f:facet>
</h:head>
<h:body>
<h:form><p:inputText/></h:form>
</h:body>
</html>
The style sheets arrived in this order (observed; res-* are the h:outputStylesheet resources, link-* the plain links, all
in the library or directory css):
| # | Mojarra 4.1.17 | MyFaces 4.1.4 |
|---|---|---|
1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
What follows from it:
-
A plain element in the
first,middleorlastfacet or directly inh:headis written where the order above puts it. Anh:outputStylesheetis a resource component: wherever it is written (in a facet too) it joins the list of registered resources and is written there. A facet therefore does not move a resource component. On Mojarra the four resource components arrived in the order body, last, first, middle; on MyFaces in the order they were declared. The probe page differs only by that. Do not rely on the relative order of resources declared in different facets. -
The application’s
h:outputStylesheetresources arrived beforecomponents.css(the likely reason is that the PrimeFaces component that pullscomponents.cssin sits in the body and is processed after the head; the order itself was observed). At equal specificitycomponents.cssand the theme therefore win over a style sheet declared withh:outputStylesheet. -
The plain
linkelements inh:heador in thelastfacet arrived after the PrimeFaces style sheets and the scripts, so their rules win. The expression#{resource['css:link-last.css']}(librarycss, namelink-last.css) produces the right URL for a resource library; see resource identifiers. -
h:outputScriptis different. In a separate run (both implementations) a script written in thefirstfacet was written in that facet, ahead oftheme.css, and scripts written inh:headand in thelastfacet came after the PrimeFaces scripts, in the places of the plain elements.
The consequence for styling is the layout the Bookshelf uses: the application’s own rules go into a plain link in the last
facet, and they are written to beat the theme by specificity, not by position:
<h:head>
<f:facet name="first">
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
</f:facet>
<title>#{msg['app.name']}</title>
<ui:insert name="head"/>
<f:facet name="last">
<link rel="stylesheet" href="#{resource['css:bookshelf.css']}"/>
</f:facet>
</h:head>
.ui-button.bookshelf-accent { background: #6f42c1; border-color: #6f42c1; }
The selector has two classes, so it beats the theme’s .ui-button rule whatever the order of the files. In headless Chrome the
button computed to rgb(111, 66, 193), the accent colour, and not to the Saga Blue rgb(33, 150, 243).
A page without h:head gets nothing. The renderers are attached to the standard tags. A page that uses the plain HTML elements
<head> and <body> rendered the PrimeFaces component markup but no link and no script of PrimeFaces on Mojarra and on
MyFaces: no theme, no icons, no widgets. Use h:head and h:body in every template and view that holds PrimeFaces
components. Faces keeps one renderer per type, so a second library that registers its own jakarta.faces.Head renderer would replace the
PrimeFaces one; that case was not tested, so check such a combination in a test.
Moving the scripts to the end of the body. primefaces.MOVE_SCRIPTS_TO_BOTTOM set to true removed every script element from
the head and wrote all of them, the PrimeFaces resources, the settings script and the initialisation scripts included, at the end
of the body (observed on the hello page: six script elements in the head and two inline widget scripts in the body without the parameter; none in
the head and six at the end of the body with it, five resource scripts and one inline script; both widgets of the page were
created in all three modes). The value defer additionally gave each resource script
a defer="defer" attribute and merged the initialisation scripts into one DOMContentLoaded handler that removes its own
element. The page paints before the scripts run, which is the performance advantage the PrimeFaces performance page names
(see the PrimeFaces part of the performance page). Test inline scripts of your own that call
PrimeFaces or jQuery, because they now run before the library is loaded.
Where the Setup Sits in the Request Processing Lifecycle
The setup features of this page touch the lifecycle (the six phases) in few places, and knowing which ones explains the theme behaviour above:
| Moment | What happens |
|---|---|
Application start |
The context parameters are read; |
Nothing of this page. A theme chooser is an ordinary input: the value is converted and validated like any other (a posted theme that is not in the menu stopped here with a validation error). |
|
|
|
|
|
Everything else. |
The Context Parameters
PrimeFaces needs no configuration ("configuration by exception"). Everything that can be configured is a context-param in
web.xml named primefaces.NAME. The table lists every name the 16.0.0 jar reads (the 22 names of the documentation’s
configuration table, plus CACHE_PROVIDER, PUBLIC_CAPTCHA_KEY and PRIVATE_CAPTCHA_KEY that belong to the cache and captcha
components, and the three standard parameters it also reads). Parameters are read once when the application starts, with two things
to know about expressions: HeadRenderer evaluates the value of THEME as a value expression on every request, and the
configuration evaluates the value of CSP as an expression once, while it is built (source). The last column says what was run.
| Parameter | Default | Effect | Checked |
|---|---|---|---|
|
|
Theme library; |
observed |
|
|
Writes |
observed |
|
|
Components with a responsive mode use PrimeFlex classes instead of Grid CSS ( |
observed |
|
|
|
observed |
|
|
Switches touch support of data table, galleria, tab view, carousel and context menu off globally; the value may be an expression |
documentation |
|
|
|
observed |
|
|
|
observed |
|
|
|
observed, effect on traffic documented |
|
|
Ajax-updated inputs are always reset |
documentation |
|
|
Makes |
source |
|
|
Client-side validation; adds |
source |
|
|
Client-side validation messages come from the server’s message interpolator |
documentation |
|
|
Bean Validation metadata becomes HTML attributes |
documentation |
|
|
An input that receives an error |
documentation |
|
|
Writes |
observed, source |
|
|
|
observed |
|
|
Content Security Policy: |
|
|
empty |
Comma separated exception classes the PrimeFaces exception handler does not log |
|
|
|
Where the multi-view state is kept: |
documentation |
|
|
Limit of streamed dynamic contents per view (source default) |
source |
|
none |
Cache provider of |
documentation |
|
none |
Keys of |
documentation |
Three standard parameters change PrimeFaces behaviour as well, because it reads them: jakarta.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
(reported to the client as considerEmptyStringNull), jakarta.faces.VALIDATE_EMPTY_FIELDS (auto validates empty fields when Bean
Validation is present, reported as validateEmptyFields; on the Tomcat scratch app without Bean Validation it was false) and
jakarta.faces.validator.DISABLE_DEFAULT_BEAN_VALIDATOR. They are described on the configuration page of this section
(validation parameters).
The documentation table is out of date on one default. CLIENT_SIDE_LOCALISATION is listed with the default false; the
PrimeFaces 14 migration guide says it "is now enabled by default" and the 16.0.0 source parses the missing parameter as true
(Objects.toString(value, "true")). Observed: without the parameter, a request with Accept-Language: es for an application that
supports es wrote locales/locale-es.js; with the explicit value false it wrote no locale script (flagged).
The web.xml the Bookshelf uses for the PrimeFaces-specific part is short. The theme is an expression (Themes), the scripts move
to the bottom, partial submit is on, and the CSP is left at its default here because the security page develops it:
<!-- the theme of the current user; see the themes section -->
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>#{primeThemeBean.name}</param-value>
</context-param>
<!-- send only what p:ajax processes -->
<context-param>
<param-name>primefaces.SUBMIT</param-name>
<param-value>partial</param-value>
</context-param>
<!-- scripts at the end of the body, deferred -->
<context-param>
<param-name>primefaces.MOVE_SCRIPTS_TO_BOTTOM</param-name>
<param-value>defer</param-value>
</context-param>
<!-- no version in resource URLs -->
<context-param>
<param-name>primefaces.HIDE_RESOURCE_VERSION</param-name>
<param-value>true</param-value>
</context-param>
HIDE_RESOURCE_VERSION removes v=16.0.0 from every PrimeFaces resource URL, which keeps the exact library version out of the
HTML. The documentation notes that it can be argued whether the version number is a security risk; it also removes the cache
buster, so after an upgrade a browser that cached components.js may keep the old file until its cache expires (the resource
handling page covers the cache headers: caching headers).
Parameters and filters that are not in the table: the org.primefaces.webapp.filter.CharacterEncodingFilter (UTF-8 unless an
encoding init parameter says otherwise) and org.primefaces.webapp.filter.NoCacheFilter (no-cache headers for views) are
filters the application maps to the FacesServlet when it wants them (documentation, not run). The
request-character-encoding and response-character-encoding elements of a Servlet 6.1 web.xml do the first job without a
filter.
Themes
A PrimeFaces theme is a resource library named primefaces-<name> that holds one file, theme.css. HeadRenderer takes the value of
primefaces.THEME (default saga-blue), evaluates it as a value expression, and writes a link to theme.css in the library
primefaces- plus that value. The theme is a style sheet for the ui-* classes that components.css and the renderers use, and it
defines the colours, the fonts and the CSS custom properties (--surface-a, --primary-color, --text-color and others) of the page.
The themes that ship
Only saga-blue is inside primefaces-16.0.0.jar. Every other theme is in the separate primefaces-themes jar (since PrimeFaces
15.0.0, when the themes moved out of the main jar), which has the same version number as PrimeFaces. The 16.0.0 themes jar holds
the theme libraries below (listed from the jar), plus the shared libraries primefaces-aura-common (fonts) and
primefaces-material-light-common, which are not themes, and a directory primefaces-mytheme that looks like a sample (its primary colour is #2196F3, as in
Saga Blue).
| Family | Theme names (value of primefaces.THEME) |
|---|---|
Saga |
|
Vela |
|
Arya |
|
Aura |
|
Bootstrap 4 |
|
Material |
|
Material compact |
|
Luna |
|
Nova |
|
Saga, Vela and Arya are the base light and dark themes. In the 16.0.0 jars their surface colour (--surface-a) was #ffffff (Saga Blue),
#1f2d40 (Vela Blue) and #1e1e1e (Arya Blue), and their primary colour (--primary-color) #2196F3, #90CAF9 and #90CAF9. Neither a
theme’s name nor its CSS says reliably whether it is dark: vela-blue, nova-dark and aura-dark-emerald all declare color-scheme:light
in their CSS. Choose a theme by looking at it in the PrimeFaces showcase (which refused scripted requests,
see the flags) and by testing the contrast of your own pages.
Choosing a theme
A fixed theme is one context-param:
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>vela-blue</param-value>
</context-param>
The behaviour of the values, run on Tomcat 11.0.26 with the primefaces-themes jar on the class path:
| Value | Result |
|---|---|
absent |
|
|
Short names still work in 16.0.0: the link used |
|
No theme link at all (the page is unstyled by the theme; |
|
Evaluated for every request (next section) |
a name that does not exist ( |
Mojarra: |
A typo in the theme name therefore produces no error on either implementation: the page just looks wrong. If a theme from the
primefaces-themes jar is selected and the jar is not on the class path, the result is the same as for a missing name.
A theme per user
Because HeadRenderer evaluates the parameter as an expression on every request, the theme can come from a bean. The Bookshelf
keeps the choice in a session-scoped bean (a user preference, not page state) and persists nothing else; a real application
would store it in the user’s profile or in a preference cookie (cookie attributes).
package org.example.bookshelf.web;
import jakarta.enterprise.context.SessionScoped;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Named;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
/** Holds the PrimeFaces theme chosen by the current user. */
@Named
@SessionScoped
public class PrimeThemeBean implements Serializable {
private static final Set<String> ALLOWED = Set.of("saga-blue", "vela-blue", "arya-blue", "luna-green");
private String name = "saga-blue";
public List<String> getChoices() {
return ALLOWED.stream().sorted().toList();
}
public String getName() {
return name;
}
public void setName(String name) {
if (ALLOWED.contains(name)) {
this.name = name;
}
}
/** Redirects to the current view so that the next response is built with the new theme only. */
public String apply() {
String viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
return viewId + "?faces-redirect=true";
}
}
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>#{primeThemeBean.name}</param-value>
</context-param>
<h:form id="themeForm" styleClass="bookshelf-theme">
<p:outputLabel for="theme" value="#{msg['theme.label']}"/>
<p:selectOneMenu id="theme" value="#{primeThemeBean.name}">
<f:selectItems value="#{primeThemeBean.choices}"/>
</p:selectOneMenu>
<p:commandButton value="#{msg['theme.apply']}" icon="pi pi-palette"
action="#{primeThemeBean.apply}" ajax="false"/>
</h:form>
Three things in the bean are deliberate. The name goes into a resource library name, so it comes from a fixed list: the setter
ignores any other value, and the menu rejects it earlier (a posted evil produced a validation error, HTTP 200, and left the theme at
saga-blue). The action returns the current view id with faces-redirect=true, and the form uses ajax="false". The reason is the
next table, which is the main pitfall of a per-user theme:
| Response to the theme form | Theme links in the HTML (both implementations) |
|---|---|
|
one: |
|
two: |
After an ordinary postback that keeps the view the old theme link came back as well, after the new one, so the old theme wins the cascade. The page showed the previous theme although the bean held the new one (the saved view is the likely source of the old link; that was not verified). Redirecting to a fresh view, which is Post/Redirect/Get as on the flash and Post/Redirect/Get page, gave one link.
Changing the theme without leaving the page. PrimeFaces has a client-side function for it, PrimeFaces.changeTheme(name), which
replaces the library name in the href of the theme link. The 10.0.0 migration guide shows it as the replacement of the removed
ThemeSwitcher component, with an ordinary menu:
<h:form id="frmTheme">
<p:selectOneMenu id="themeSelectMenu" widgetVar="themeMenu" value="#{primeThemeBean.name}">
<f:selectItems value="#{primeThemeBean.choices}"/>
<p:ajax process="@this"
oncomplete="PrimeFaces.changeTheme($('#frmTheme\\:themeSelectMenu_label').text());"/>
</p:selectOneMenu>
</h:form>
In headless Chrome, choosing vela-blue in the opened menu sent the value through p:ajax (a later request of the same session
rendered ln=primefaces-vela-blue) and changed the link in the open page; the button changed from rgb(33, 150, 243) to
rgb(144, 202, 249). Calling PrimeFaces.changeTheme('vela-blue') from the console changes the page in the same way. The function changes only the browser; the next full page request uses whatever the
server-side expression returns, which is why the menu above also binds the value to the bean.
A custom theme
There are two routes, and the first one can be run in minutes.
Extend a ready-made theme. A theme is just a style sheet in a library named primefaces-<name>, and Faces evaluates value
expressions inside style sheet resources (expressions inside resource files). A theme can
therefore import another theme and override rules after it:
@import url("#{resource['primefaces-saga-blue:theme.css']}");
/* Bookshelf brand colour on top of Saga Blue */
.ui-button:not(.ui-button-secondary) { background: #6f42c1; border-color: #6f42c1; }
.ui-button:not(.ui-button-secondary):enabled:hover { background: #5a32a3; border-color: #5a32a3; }
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>bookshelf</param-value>
</context-param>
On Mojarra and MyFaces the request for the theme returned the file with
@import url("/bookshelf/jakarta.faces.resource/theme.css.xhtml?ln=primefaces-saga-blue&v=16.0.0"); in its first line, and in headless Chrome
a p:commandButton computed to rgb(111, 66, 193), the brand colour. This costs a second request for the imported file and
it relies on the selectors of the imported theme (the :not(...) guard keeps the secondary buttons of the theme intact); it is
fine for small adjustments and for a prototype.
Build a theme from the sources. A production theme is compiled from SCSS. The primefaces-themes module of the PrimeFaces
repository holds theme-base (the layout and structure of all components) and themes (one folder per theme with
_variables.scss, _extensions.scss and a theme.scss that imports the variables, the base and the extensions). The 16.0.0 files of
Saga Blue start like this, and the build is mvn dart-sass:compile-sass (README of the module):
@import './variables';
@import '../../theme-base/_components';
@import './_extensions';
/* _variables.scss */
$primaryColor: #2196F3 !default;
$primaryTextColor: #ffffff !default;
$shade000: #ffffff !default; // surface
$shade700: #495057 !default; // text color
A new theme is a new folder with its own variables, built by the same Maven plugin into META-INF/resources/primefaces-<name>/theme.css
in a jar or a resources/primefaces-<name>/theme.css folder in the WAR; the _extensions.scss file is the place for
customisations (its comment says "Customizations to the designer theme should be defined here"). The PrimeFaces documentation also
points to a community template repository that creates a theme without forking the whole module. The SCSS route was read from
the sources and not compiled for this page. The theme designer, the visual tool that produces such SCSS themes (the comment in
_extensions.scss speaks of "the designer theme"), could not be examined: the vendor’s web site answers scripted requests with a
bot-protection page that this work does not bypass, so the tool is not described here; both points are listed in the flags.
Themes and components that no longer exist
-
ThemeRoller themes. Until PrimeFaces 14 the themes were jQuery UI ThemeRoller style sheets, distributed as the
org.primefaces.themesartifacts and picked from a gallery. The 15.0.0 migration guide states that "Legacy ThemeRoller themes are no longer supported and will not render correctly". A theme name from a book such asblueskyorcupertinodoes not exist in 16. -
p:themeSwitcher. Deprecated in 10.0.0 and removed in 11.0.0; it is not among the 176 tags of the 16.0.0 tag library. Use a menu andPrimeFaces.changeThemeor the per-user bean above. -
The
aristoandomegathemes were removed in 10.0.0 andsagabecame the default; the settingprimefaces.THEME_FORMSdisappeared in 3.1.
Icons: PrimeIcons and Font Awesome
PrimeIcons is the icon font of the PrimeTek libraries. It is part of the PrimeFaces jar (the font in five formats under
primefaces/vendor/primeicons/fonts and primeicons/primeicons.css), HeadRenderer includes it by default, and the parameter
primefaces.PRIME_ICONS set to false removes the style sheet (observed). Icons are CSS classes, pi plus pi-<name>, used on
any element or in the icon attribute of components such as p:commandButton:
<h1><i class="pi pi-book"></i> PrimeIcons and <i class="fa-solid fa-book"></i> Font Awesome</h1>
<h:form id="actions">
<p:commandButton id="pi" value="Search" icon="pi pi-search" type="button"/>
<p:commandButton id="fa" value="Borrow" icon="fa-solid fa-book" type="button"/>
<p:commandButton id="only" icon="pi pi-trash" type="button" title="Delete"/>
</h:form>
The button with icon="pi pi-search" rendered <span class="ui-button-icon-left ui-icon ui-c pi pi-search"> before its label, and in headless
Chrome the ::before content of the icon used the font family primeicons, which the browser reported as loaded. A button without a value
and with a title rendered the title as its text (ui-button-icon-only), which gives an icon-only button an accessible name; give every
icon-only control a title or an aria-label.
Font Awesome was removed from the PrimeFaces jar in 11.0.0. The documentation says PrimeFaces supports Font Awesome 4.x, 5.x and
6.x or later added by the application as a WebJar. The icons are used the same way (icon="fa-solid fa-book", or a plain <i>) once the
style sheet is on the page. The style sheet is the part that needs care, and the check below was run on both implementations:
<ui:composition template="/WEB-INF/templates/layout.xhtml">
<ui:define name="head">
<h:outputStylesheet library="webjars" name="font-awesome/6.7.2/css/all.min-jsf.css"/>
</ui:define>
...
</ui:composition>
| WebJar and style sheet | Files named *-jsf.css in the WebJar |
Font in headless Chrome (Mojarra and MyFaces) |
|---|---|---|
|
yes |
loaded |
|
yes |
loaded |
|
yes |
error (the font file was not found) |
|
no (the latest WebJar at the time of writing has none) |
error |
The -jsf variants exist because the font URLs inside the standard style sheet are relative (../webfonts/...), and the URL of a
resource served by Faces carries the library as a query parameter (?ln=webjars), which a relative URL cannot express (that is the
likely reason; the failure itself, a font in the state error, was observed). The
-jsf style sheets replace those URLs with value expressions (the 6.7.2 file contains
url("#{resource['webjars:font-awesome/6.7.2/webfonts/fa-brands-400.woff2']}&#")) and Faces evaluates them. The practical rules: use the
*-jsf.css file, and before upgrading the WebJar check that it still contains the -jsf files (the 7.3.0 WebJar does not). Pin the
version in the library path, as font-awesome/6.7.2/... does; the version is part of the resource name.
Responsive Layout: ui-fluid, Grid CSS, PrimeFlex and panelGrid
The PrimeFaces documentation names three ingredients of a responsive page: the page layout (menu, header, content, footer, which is plain HTML and CSS of the application), a grid framework that places the content, and components that adapt to their container. PrimeFaces gives the last two a vocabulary.
Fluid components
Form components have a fixed width by default. Putting them in a container with the class ui-fluid makes them take the full width
of the container, which is what a grid cell needs (p:selectOneMenu has autoWidth, whose default auto since 13.0.0 notices a
parent ui-fluid and skips its own width calculation). Complex components such as p:dialog, charts, the carousel and the pick
list have a responsive attribute that makes them react to the screen size (documentation, not run). Touch features (swipe on the
tab view, long press for the context menu) are on by default and primefaces.TOUCHABLE switches them off globally.
Grid CSS
Grid CSS is a 12-column fluid grid built into components.css. A container has the class ui-g; its columns have ui-g-1 to
ui-g-12, ui-g-offset-N moves a column, ui-g-nopad removes the padding, and the prefixes ui-sm-N, ui-md-N, ui-lg-N
and ui-xl-N override the width above or below a breakpoint. The breakpoints are in the 16.0.0 components.css:
| Prefix | Media query in components.css |
Device named in the documentation |
|---|---|---|
|
|
phones |
|
|
tablets |
|
|
desktops |
|
|
big screens |
<div class="ui-g">
<div class="ui-g-12 ui-md-6 ui-lg-3">one</div>
<div class="ui-g-12 ui-md-6 ui-lg-3">two</div>
<div class="ui-g-12 ui-md-6 ui-lg-3">three</div>
<div class="ui-g-12 ui-md-6 ui-lg-3">four</div>
</div>
The older Grid CSS of the PrimeFaces 5 era, ui-grid, ui-grid-row and ui-grid-col-N (with ui-grid-responsive), is still in the
16.0.0 components.css and still used by some renderers (the default p:panelGrid wraps its rows in ui-grid ui-grid-responsive). The
10.0.0 migration guide deprecated Grid CSS in favour of PrimeFlex, and the 15.0.0 guide deleted the "grid" layouts of some
components, so new layouts should use PrimeFlex unless a component needs Grid CSS.
PrimeFlex (the flex grid)
The flex-based grid, "Flex Grid CSS" in the PrimeFaces documentation, is PrimeFlex, a library shared by PrimeFaces, PrimeNG and
PrimeReact. It is not in the PrimeFaces jar. The documentation adds it as a WebJar and includes the style sheet from the webjars library:
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>primeflex</artifactId>
<version>4.0.0</version>
</dependency>
<h:head>
<title>Grid</title>
<h:outputStylesheet library="webjars" name="primeflex/4.0.0/primeflex.min.css"/>
</h:head>
<h:body>
<div class="grid">
<div class="col-12 md:col-6">one</div>
<div class="col-12 md:col-6">two</div>
</div>
</h:body>
With the WebJar of PrimeFlex 4.0.0 on the class path the stylesheet was served (the library name webjars is the directory
META-INF/resources/webjars of the jar) and the container computed to display:flex with flex-wrap:wrap. PrimeFaces 16 uses PrimeFlex
4.0.0, whose colour variables are --p-red-500 instead of --red-500 (16.0.0 migration guide); PrimeFlex 3 had changed the class names already (PrimeFaces 11 and 12 migration guides), and PrimeFaces ships a CLI tool to migrate pages from PrimeFlex 2 to 3.
The parameter primefaces.FLEX tells the components that have a responsive mode to emit PrimeFlex classes instead of Grid CSS
classes. Observed: p:selectOneRadio layout="responsive" rendered class="ui-grid ui-grid-responsive" over ui-g and
ui-g-12 ui-md-6 cells without the parameter, and class="ui-grid-responsive" over grid and col-12 md:col-6 cells with
FLEX=true. A p:panelGrid layout="grid" did not change (its layout is chosen by the attribute). The documentation says "not
implemented by all components yet"; the 16.0.0 attributes flex exist on p:dataGrid, p:dataView, p:datePicker,
p:orderList, p:selectManyCheckbox and p:selectOneRadio.
p:panelGrid layouts
p:panelGrid is the layout component for forms. Its layout attribute selects the markup; the rendered output for the same
two cells in each mode was (class names from the run; the columns value must be a divisor of 12 for the grid layouts since 13.0.0):
layout |
Rendered structure | Needs |
|---|---|---|
|
|
nothing |
|
|
Grid CSS (in |
|
|
PrimeFlex |
|
|
Tailwind CSS (the application provides it) |
columnClasses sets the classes of the cells, and styleClass="ui-noborder" (or ui-panelgrid-blank) removes the borders. A form
with the labels at a quarter of the width on tablets and larger, and the fields at three quarters, is written once with Grid CSS
and once with PrimeFlex:
<div class="ui-fluid">
<p:panelGrid columns="2" layout="grid" styleClass="ui-noborder"
columnClasses="ui-g-12 ui-md-3, ui-g-12 ui-md-9">
<p:outputLabel for="title" value="Title"/>
<p:inputText id="title"/>
<p:outputLabel for="author" value="Author"/>
<p:inputText id="author"/>
</p:panelGrid>
</div>
<div class="ui-fluid">
<p:panelGrid columns="2" layout="flex" styleClass="ui-noborder"
columnClasses="col-12 md:col-3, col-12 md:col-9">
<p:outputLabel for="title" value="Title"/>
<p:inputText id="title"/>
<p:outputLabel for="author" value="Author"/>
<p:inputText id="author"/>
</p:panelGrid>
</div>
In headless Chrome at a window width of 1280 pixels the two cells of a row measured 316 and 948 pixels (Grid CSS) and 320 and 960
pixels (PrimeFlex), a quarter and three quarters; at 756 pixels, below the tablet breakpoint, every cell was the full 756 pixels
wide in both. The documentation warns that labels may not line up with the fields in horizontal forms and suggests
align-items:center on .ui-panelgrid-content through a style class.
Localisation
PrimeFaces has two places for localised text, the server-side message bundles and the client-side locale scripts, and both are chosen from the Faces locale of the view.
The Faces locale. Which locale PrimeFaces uses is the locale of the view. An application has to declare the locales it supports
in faces-config.xml: in the scratch application, without <supported-locale>es</supported-locale> a request with
Accept-Language: es was answered with locale:'en_US' in PrimeFaces.settings; with it, the settings carried locale:'es'
(see locale selection).
<application>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>es</supported-locale>
</locale-config>
<resource-bundle>
<base-name>org.example.bookshelf.messages</base-name>
<var>msg</var>
</resource-bundle>
</application>
Server-side messages. The messages of the components (validation, empty table, file limits) live in org/primefaces/Messages.properties
in the jar, with a translation per language: the 16.0.0 jar holds Messages_<language>.properties for Czech, German, Greek, Spanish,
Persian, French, Croatian, Hindi, Indonesian (in), Italian, Japanese, Georgian, Korean, Lithuanian, Latvian, Dutch, Norwegian, Polish,
Portuguese, Romanian, Russian, Slovak, Swedish, Turkish and Chinese, and an English file. A language that is missing is added, and a
shipped message is changed, by putting a file of the same name in WEB-INF/classes (or in an application jar earlier on the class path):
primefaces.data.EMPTY_MESSAGE=Todav\u00eda no hay libros en el cat\u00e1logo.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="jakarta.faces.html" xmlns:p="primefaces">
<h:head><title>empty</title></h:head>
<h:body>
<p:dataTable id="t" value="#{emptyBean.books}" var="b">
<p:column headerText="Title"><h:outputText value="#{b}"/></p:column>
</p:dataTable>
</h:body>
</html>
package org.example.bookshelf.web;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
import java.util.List;
@Named
@RequestScoped
public class EmptyBean {
public List<String> getBooks() {
return List.of();
}
}
Observed on Mojarra and on MyFaces: with the file, Accept-Language: en gave "No records found." and Accept-Language: es gave
"Todavía no hay libros en el catálogo."; without it the shipped Spanish text "No se encontraron registros." appeared. The \uXXXX escapes in
the file work with any file encoding.
Client-side texts. The widgets (date picker, filter menus, paginator tips, upload buttons) read their texts and the names of days
and months from a JavaScript object, PrimeFaces.locales['<language>'], defined by locales/locale-<language>.js of the
library primefaces. The 16.0.0 jar contains 48 of them, with English as the default. With primefaces.CLIENT_SIDE_LOCALISATION enabled,
which is the default (The Context Parameters), the head renderer adds the script of the current language, and nothing else is needed:
<!-- observed for Accept-Language: es, no parameter in web.xml -->
<script src="/bookshelf/jakarta.faces.resource/locales/locale-es.js.xhtml?ln=primefaces&v=16.0.0"></script>
A page can also load one script by hand, <h:outputScript name="locales/locale-nl.js" library="primefaces"/>, for a language that the
Faces locale does not select. A language PrimeFaces does not ship is defined in your own script by assigning a complete object to
PrimeFaces.locales['xx']; the documentation lists the keys of the English object (day and month names, firstDayOfWeek, the filter
and paginator texts). The client scripts and the server bundles are independent: translate both.
Putting It Together: the Bookshelf Shell
The pieces above make the shell of the PrimeFaces variant of the Bookshelf catalogue (the earlier pages of this section build the
plain Faces version). The template carries the head settings, the theme chooser and the message area; a page defines the content.
Compared with the plain-Faces template of the templating page (templating) the differences are the p:
tags, the PrimeIcons in the header and the last facet:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="jakarta.faces.core"
xmlns:h="jakarta.faces.html"
xmlns:ui="jakarta.faces.facelets"
xmlns:p="primefaces">
<f:view contentType="text/html" encoding="UTF-8">
<h:head>
<f:facet name="first">
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
</f:facet>
<title>#{msg['app.name']}</title>
<ui:insert name="head"/>
<f:facet name="last">
<link rel="stylesheet" href="#{resource['css:bookshelf.css']}"/>
</f:facet>
</h:head>
<h:body>
<header class="bookshelf-header">
<span class="bookshelf-brand"><i class="pi pi-book"></i> #{msg['app.name']}</span>
<h:form id="themeForm" styleClass="bookshelf-theme">
<p:outputLabel for="theme" value="#{msg['theme.label']}"/>
<p:selectOneMenu id="theme" value="#{primeThemeBean.name}">
<f:selectItems value="#{primeThemeBean.choices}"/>
</p:selectOneMenu>
<p:commandButton value="#{msg['theme.apply']}" icon="pi pi-palette"
action="#{primeThemeBean.apply}" ajax="false"/>
</h:form>
</header>
<main>
<p:messages id="messages" showDetail="true" closable="true"/>
<ui:insert name="content"/>
</main>
</h:body>
</f:view>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="jakarta.faces.core"
xmlns:h="jakarta.faces.html"
xmlns:ui="jakarta.faces.facelets"
xmlns:p="primefaces">
<ui:composition template="/WEB-INF/templates/layout.xhtml">
<ui:define name="content">
<h1>#{msg['catalogue.title']}</h1>
<h:form id="search">
<div class="ui-fluid">
<p:panelGrid columns="2" layout="grid" styleClass="ui-noborder"
columnClasses="ui-g-12 ui-md-3, ui-g-12 ui-md-9">
<p:outputLabel for="q" value="#{msg['catalogue.search']}"/>
<p:inputText id="q" value="#{param.q}"/>
</p:panelGrid>
</div>
<p:commandButton value="#{msg['catalogue.search.button']}" icon="pi pi-search"
styleClass="bookshelf-accent" ajax="false"/>
</h:form>
<p:dataTable id="books" value="#{catalogueBean.books}" var="book">
<p:column headerText="Title"><h:outputText value="#{book.title}"/></p:column>
<p:column headerText="Author"><h:outputText value="#{book.author}"/></p:column>
<p:column headerText="Year"><h:outputText value="#{book.year}"/></p:column>
</p:dataTable>
</ui:define>
</ui:composition>
</html>
app.name=Bookshelf
catalogue.title=Catalogue
catalogue.search=Search titles
catalogue.search.button=Search
theme.label=Theme
theme.apply=Apply
# messages_es.properties
app.name=Estanter\u00eda
catalogue.title=Cat\u00e1logo
catalogue.search=Buscar t\u00edtulos
catalogue.search.button=Buscar
theme.label=Tema
theme.apply=Aplicar
On Mojarra 4.1.17 and MyFaces 4.1.4 the catalogue answered HTTP 200 with four table rows, the theme form switched the theme through
the redirect (the theme link changed from saga-blue to arya-blue), and the accent button computed to rgb(111, 66, 193) in
headless Chrome. The search field is a plain value read from #{param.q} and only shows the form. The other PrimeFaces pages of this section
(PrimeFaces Ajax, forms and validation; PrimeFaces data components; PrimeFaces panels, menus and dialogs; PrimeFaces files, media,
charts and drag and drop) replace the table with a lazy model, the ajax="false" button with p:ajax, and add dialogs, menus and
uploads to this shell.
Checking the Setup from the Command Line
The failures of this page are silent (an unstyled page, a font that does not load), so check the result instead of trusting the
browser’s first impression. The three requests below are enough; the output is from the Tomcat scratch application with
primefaces.THEME set to vela-blue (the ;jsessionid= parts disappear once the client sends the session cookie):
# which theme and which PrimeFaces style sheets does the page link?
curl -s http://localhost:8080/bookshelf/catalogue.xhtml | grep -o 'href="[^"]*\(theme\|primeicons\|components\)\.css[^"]*"'
# href="/bookshelf/jakarta.faces.resource/theme.css.xhtml?ln=primefaces-vela-blue&v=16.0.0"
# href="/bookshelf/jakarta.faces.resource/primeicons/primeicons.css.xhtml?ln=primefaces&v=16.0.0"
# href="/bookshelf/jakarta.faces.resource/components.css.xhtml?ln=primefaces&v=16.0.0"
# is the theme served?
curl -s -o /dev/null -w '%{http_code} %{content_type} %{size_download}\n' \
'http://localhost:8080/bookshelf/jakarta.faces.resource/theme.css.xhtml?ln=primefaces-vela-blue&v=16.0.0'
# 200 text/css 218530
curl -s -o /dev/null -w '%{http_code}\n' \
'http://localhost:8080/bookshelf/jakarta.faces.resource/theme.css.xhtml?ln=primefaces-nosuch&v=16.0.0'
# 404
# what does the client script believe?
curl -s http://localhost:8080/bookshelf/catalogue.xhtml | grep -o 'PrimeFaces.settings={[^}]*}'
# PrimeFaces.settings={locale:'en',viewId:'/catalogue.xhtml',contextPath:'\/bookshelf',cookiesSecure:false,cookiesSameSite:'Strict',validateEmptyFields:false,considerEmptyStringNull:false}
The same three checks belong in an integration test of the application (the testing page builds on them; PrimeFaces Selenium drives the PrimeFaces widgets). In a
browser, PrimeFaces.settings and the network tab of the developer tools show the same facts, and document.fonts lists the
icon fonts and whether each one is loaded or in error, which is how the Font Awesome table above was produced.
Where the Other PrimeFaces Topics Are
This page stops at the shell of the application. The components and their behaviour are on the pages that follow in this group:
PrimeFaces Ajax, forms and validation (p:ajax, process and update with their search expressions (see also PrimeFaces search expressions), partial submit, p:remoteCommand, the input components,
client-side validation, p:growl and p:messages); PrimeFaces data components (p:dataTable, LazyDataModel, trees, data export);
PrimeFaces panels, menus and dialogs (panels, tab view, menus, p:dialog and the dialog framework); PrimeFaces files, media,
charts and drag and drop; PrimeFaces Extensions; OmniFaces; and the page about other component libraries (BootsFaces, Tobago and
the discontinued libraries of the older books). Where PrimeFaces runs is covered by Tomcat and Weld, Jakarta EE servers,
Spring Boot with JoinFaces and Quarkus. A reader who needs one of those first can start there and come back here for the
theme and the configuration.
Security Settings of the Setup
The setup decisions of this page have security consequences that the later PrimeFaces pages build on:
-
Content Security Policy.
primefaces.CSPswitches PrimeFaces to nonce-stamped scripts and registered handlers instead of inline code. The security page ran it (p:commandButtonworked on Mojarra and MyFaces) and explains the limitations (Content Security Policy). Moving the scripts to the bottom (The Head: What PrimeFaces Writes and in Which Order) does not replace it. -
Rich text is untrusted markup.
p:textEditorrefuses to render without the OWASP sanitizer unlesssecure="false"is set (The Dependency and the Optional Libraries). Leavesecureat its default for anything another user will read. The component documentation states the sanitizer is there "to prevent XSS". -
The theme name is a resource name. A theme taken from a request parameter, a cookie or a profile reaches
HeadRendereras a library name. Validate it against a fixed list asPrimeThemeBeandoes (A theme per user) and store only the name. -
Version disclosure.
v=16.0.0in every PrimeFaces URL tells an attacker the exact library version.HIDE_RESOURCE_VERSIONremoves it (The Context Parameters); keep the library patched either way. -
Cookies.
COOKIES_SAME_SITE(Strictby default) covers the cookies PrimeFaces' JavaScript writes. The session cookie and the cookies of the Faces implementation have their own settings, described on the security page. -
Keys and credentials.
PUBLIC_CAPTCHA_KEYandPRIVATE_CAPTCHA_KEYarecontext-paramvalues in the documentation’s examples. The private key is a secret: keep it out of the repository and ofweb.xmlin version control, and give it to the server through its own deployment configuration. This page has no example key on purpose. -
Uploads.
p:fileUploadhas limits and validators of its own; the upload and download page sets the posture (size limits, content sniffing, file name sanitising) that the PrimeFaces files page reuses (upload limits, validating the content). -
View state. Components are ordinary Faces components, so the rule of the security page applies: view state protects against cross-site request forgery only with server-side state saving (cross-site request forgery).
Mojarra and MyFaces Compared
PrimeFaces is written for both implementations and the pages of this section behaved the same on both, apart from the following (all observed with Mojarra 4.1.17 and MyFaces 4.1.4 on Tomcat 11.0.26 and Weld 6.0.4.Final):
| Topic | Mojarra 4.1.17 | MyFaces 4.1.4 |
|---|---|---|
|
writes |
writes no theme link |
Order of |
body, last, first, middle |
declaration order: body, first, middle, last |
Client ids generated for components without an |
|
|
Theme link after a postback that re-renders the view |
new and old link |
new and old link (the same) |
Hello-world, head order and theme switch on Faces 4.0 |
Mojarra 4.0.26 ran them unchanged |
not run |
Expression |
worked on 4.1.17; on Mojarra 4.0.26 with Tomcat 11.0.26 the page failed with a |
worked on 4.1.4 |
Content Security Policy |
has its own nonce setting, |
no CSP support of its own; |
What Changed per Version
PrimeFaces versions move fast and change defaults in every release, so a page or a book is only as good as its PrimeFaces version. The entries below are the ones that matter for this page, from the PrimeFaces migration guides and the 16.0.0 source:
| Version | Change |
|---|---|
3.0 / 3.1 |
Aristo is the built-in theme (3.0); ThemeSwitcher is reimplemented as a native widget (3.0); |
5.0 / 6.0 |
Widgets are referenced through |
7.0 |
|
8.0 |
Java 8 or later; |
10.0.0 |
|
11.0.0 |
Font Awesome and ThemeSwitcher removed from the jar; PrimeFlex 3 (a breaking release) arrives |
12.0.0 |
PrimeFlex 3 is the version to use |
13.0.0 |
|
14.0.0 |
Java 11 is the minimum; Faces 2.0 to 2.2 support is removed; |
15.0.0 |
ThemeRoller themes are no longer supported; every theme except Saga Blue moves to |
16.0.0 |
Java EE and |
Source: PrimeFaces migration guide 16.0.0 and 15.0.0, 13.0.0 and 10.0.0
The Faces versions matter as well: the jakarta.faces.* namespaces of Faces 4.0 are the ones the PrimeFaces documentation uses for
h: and f:, and a PrimeFaces 16 application cannot run on Faces 2.x or 3.x. The documentation tree of the v16.0.0 tag already
holds a 17_0_0 folder, a development copy: no PrimeFaces 17 release exists at the time of writing and nothing on this page
applies to it. See also the
versions and implementations page of this section (Versions and Implementations).
Where the Books Are Outdated
PrimeFaces Cookbook, Second Edition (Çalışkan and Varaksin, Packt, 2015; PrimeFaces 5.1 and 5.2 on JSF 2.2) is the book behind this page: its first chapters cover setup, internationalisation and resource ordering, theming, icons, and panels and layouts. Its approach to organising a PrimeFaces application is still sound; the details are not.
-
The platform. The book is written for
javax.faceson JSF 2.2; PrimeFaces 14.0.0 removed Faces 2.x support and 16.0.0 removedjavax.*altogether. Every namespace, import and server setup needs the Jakarta Faces 4.0 or later form. Thep:namespacehttp://primefaces.org/uistill works andprimefacesis the short form. -
Resource files. The 5.x scripts were collected in
primefaces.js; since 6.0 they arecore.jsandcomponents.js(plus jQuery), and in 16 the head renderer includes them, not an explicit tag or include. Nothing has to be added by hand; a custom@ResourceDependencythat namesprimefaces.jshas to change. -
Themes. The book teaches ThemeRoller-style themes, the theme switcher component and Maven artifacts for extra themes. In PrimeFaces 16 ThemeRoller themes do not render (15.0.0),
p:themeSwitcherdoes not exist (11.0.0), and the extra themes are Saga, Vela, Arya, Aura, Bootstrap, Material, Luna and Nova in the singleprimefaces-themesjar. The setting is stillprimefaces.THEME, but the names are different. Custom themes are built from SCSS or extended with CSS, as in A custom theme. -
Icons. Font Awesome came with the jar in the book’s era; it was removed in 11.0.0. PrimeIcons (
pi pi-*) is the default and Font Awesome is added as a WebJar with the-jsfstyle sheet (Icons: PrimeIcons and Font Awesome). -
Grid CSS. The book’s layout recipes use the Grid CSS of its day (
ui-grid,ui-grid-row,ui-grid-col-N). The classes still ship in 16.0.0, but Grid CSS was deprecated in 10.0.0 in favour of PrimeFlex, which is a separate WebJar with its own class names (grid,col-12 md:col-6), andp:panelGridhas theflexlayout for it (Responsive Layout: ui-fluid, Grid CSS, PrimeFlex and panelGrid). -
Resource ordering. The book’s advice on the order of style sheets and scripts rests on the head rendering of PrimeFaces 5. The facets
first,middleandlastofh:headstill exist, but they order plain markup, noth:outputStylesheetcomponents, and the order differs between Mojarra and MyFaces for the latter (The Head: What PrimeFaces Writes and in Which Order). -
Internationalisation. The mechanism (bundles for the components, client-side locale scripts) is the same idea, but client-side localisation is on by default since 14.0.0 and the languages and keys are different (Localisation).
Other books touch this page too. Learning PrimeFaces Extensions Development (Jonna, 2014) sets up a PrimeFaces Extensions 1.2.1 project against PrimeFaces 4.0; the PrimeFaces Extensions page of this section covers the present setup. JSF 2.0 Cookbook (Leonard, 2010) was written for PrimeFaces 2.0 alongside RichFaces and Tomahawk; nothing of its PrimeFaces setup applies. None of the book content is reproduced here.
Common Mistakes
-
Plain
<head>and<body>in a template. No theme, no icons, no widgets; the components are rendered as bare markup (The Head: What PrimeFaces Writes and in Which Order). Useh:headandh:body. -
A typo in
primefaces.THEME, or a theme name fromprimefaces-themeswithout the jar. An unstyled page and, on Mojarra, aRES_NOT_FOUNDlink; there is no error. Check the link in the page source after changing the theme (Choosing a theme). -
Re-rendering the view after the user changes the theme. The old theme link is written as well, and it wins. Redirect to a fresh view (A theme per user).
-
Putting a user-chosen string into
primefaces.THEME. It becomes a library name. Allow a fixed list. -
Overriding PrimeFaces CSS with an
h:outputStylesheet. It arrives beforecomponents.css. Use a plainlinkwith#{resource[...]}in thelastfacet and select with more specificity than the theme (The Head: What PrimeFaces Writes and in Which Order). -
Depending on facets to order
h:outputStylesheetcomponents. Facets order plain markup only, and the two implementations disagree about resource components (The Head: What PrimeFaces Writes and in Which Order). -
Hello world without the sanitizer. The official
p:textEditorpage answers HTTP 500 untilowasp-java-html-sanitizeris on the class path; the cure is the dependency, notsecure="false". -
Font Awesome with the plain style sheet, or with the WebJar 7.3.0. The icons render as empty boxes because the font is not found. Use the
*-jsf.cssfile and check that the version you choose still has it (Icons: PrimeIcons and Font Awesome). -
Trusting the documentation’s configuration table for
CLIENT_SIDE_LOCALISATION. The table saysfalse; the default istrue(The Context Parameters). -
Relying on
saga,aryaandvelashort names. They still work in 16.0.0 but were announced for removal; use the-bluenames. -
Mixing PrimeFlex and Grid CSS in one form without meaning to.
p:panelGriddefaults to Grid CSS even whenprimefaces.FLEXistrue; the attributelayout="flex"and the PrimeFlex style sheet go together. -
Reading
PrimeFaces.settingsas if it were configuration. It is generated on every page from the context parameters; changeweb.xml. -
A
WELD-000119flood taken for a failure. TheINFOlines on a servlet container without Bean Validation or Persistence (What PrimeFaces Adds to Faces) mean that optional features are off. -
Different PrimeFaces and
primefaces-themesversions. They are released together; keep the same number in the POM. -
Hard-coded keys. No captcha key, API key or private value in
web.xml, a bean or a page (Security Settings of the Setup).