Facelets Templating

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 Jakarta Faces 4.1 (API jakarta.faces-api 4.1.2, part of Jakarta EE 11), Eclipse Mojarra 4.1.17 and Apache MyFaces Core 4.1.4, with Java 17 or later. The Facelets namespace is jakarta.faces.facelets in Faces 4.0 and later; Faces 4.0 behaves the same for everything below. Every snippet and every statement about the rendered output was run for real: the files were deployed in a scratch Bookshelf WAR served by Tomcat 11.0.26 with Weld 6.0.4.Final, once with Mojarra 4.1.17 and once with MyFaces 4.1.4, requested with curl, and the HTML shown or described is what came back (checked on 2026-10-08). Where the two implementations answered differently the text says so, and the differences are collected in Mojarra and MyFaces.

A web application is full of pages that share a skeleton: the same head, the same header, navigation and footer, with only the middle changing. Facelets solves this with templating: one file, the template, writes the skeleton once and marks the places where pages differ; every page, called a template client, names the template and supplies the content for those places. The tags live in the ui library, whose prefix is conventionally ui. The page covers every tag of that library, in the order a reader meets them: the template and its client, slots and their defaults, nested templates, the tags that reuse a fragment, the tags that create components, the tags that remove or debug, the place of f:metadata in a template, templates packaged in a JAR, and where Mojarra and MyFaces differ. How a Facelets file is turned into a view is explained on the Facelets and XHTML views page.

The ui Tag Library at a Glance

The Facelets templating tag library has eleven tags. The last column was measured: a page that used every tag was built on both implementations and the component tree of the view was printed. A tag that is only a tag handler runs while the view is built and leaves nothing in the tree except the text it produced; a tag that is a component stays in the tree and is evaluated again on every request.

Tag Purpose Attributes in the 4.1 VDL In the component tree

ui:composition

Root of a template client or of a reusable fragment; optionally applies a template. Everything outside it is discarded.

template

No

ui:decorate

Like ui:composition, but the markup around the tag is kept. Applies a template to a region.

template

No

ui:define

Names the content that fills one slot of a template.

name (required)

No

ui:insert

A slot in a template; its body is the default content. Without a name it receives the whole body of the client.

name

No

ui:include

Includes another Facelets file at this point.

src (required)

No

ui:param

Passes a variable to an included file or to a template.

name, value (both required)

No

ui:component

Like ui:composition without a template, but also creates a component. Everything outside it is discarded.

id, binding, rendered

Yes, one component for the tag

ui:fragment

Like ui:component, but the markup around the tag is kept.

id, binding, rendered

Yes, one component for the tag

ui:repeat

Iterates its body over a collection, one set of children for all rows.

value, var (required); varStatus, begin, end, offset, size, step, rendered, rowStatePreserved

Yes (UIRepeat)

ui:remove

Deletes its body when the file is compiled.

none

No

ui:debug

Adds the debug window script.

hotkey, rendered

Yes (UIDebug)

The measured tree of a page that used ui:include, ui:decorate, ui:define, ui:component, ui:fragment, ui:remove, ui:repeat and ui:debug in a template client contained, below the body, only UIInstructions for the text produced by the includes, defines and decorations, two components of the implementation’s ComponentRef class (one for the ui:component and one for the ui:fragment), a UIRepeat and a UIDebug; the h:outputText inside ui:remove was not there. ComponentRef is an implementation class, so a page should only rely on the tag, never on the class.

Templates and Template Clients

A template is an ordinary XHTML Facelets file that contains one or more <ui:insert name="..."> elements. Each is an insertion point (a slot) with a name. A template client is a view whose root is a <ui:composition> with a template attribute holding the template’s path. Inside the composition, one <ui:define name="..."> per slot supplies the content for that slot. When the view is built, Facelets loads the template, and each ui:insert is replaced by the ui:define of the same name, or keeps its own body when the client defines nothing for it.

A template client with two ui:define elements feeding the title and content insertion points of a layout template, while the nav and footer slots keep their default content, producing the composed view

The Bookshelf keeps its template under /WEB-INF/templates/layout.xhtml. Files under WEB-INF can never be requested directly by a browser, so a template can only be reached through the views that use it, which is the point:

WEB-INF/templates/layout.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:ui="jakarta.faces.facelets">
<h:head>
  <title><ui:insert name="title">Bookshelf</ui:insert></title>
</h:head>
<h:body>
  <header>Bookshelf</header>
  <nav>
    <ui:insert name="nav">
      <a href="index.xhtml">Home</a>
    </ui:insert>
  </nav>
  <main>
    <ui:insert name="content"/>
  </main>
  <footer>
    <ui:insert name="footer">(c) Bookshelf</ui:insert>
  </footer>
</h:body>
</html>

The template declares four slots. title, nav and footer have default content between their tags; content has none. A page that uses it:

catalogue.xhtml, a template client
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:ui="jakarta.faces.facelets">
<body>
this text is outside ui:composition and is discarded
<ui:composition template="/WEB-INF/templates/layout.xhtml">
  <ui:define name="title">Catalogue</ui:define>
  <ui:define name="content">
    <p>The catalogue goes here.</p>
  </ui:define>
</ui:composition>
</body>
</html>

Requesting that view returned the composed page, with the client’s title and content and the template’s defaults for nav and footer:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head>
  <title>Catalogue</title></head><body>
  <header>Bookshelf</header>
  <nav>
      <a href="index.xhtml">Home</a>
  </nav>
  <main>
    <p>The catalogue goes here.</p>
  </main>
  <footer>(c) Bookshelf
  </footer></body>
</html>

Three behaviours are worth remembering:

  • Everything outside <ui:composition> is ignored. The html, body and the loose text in the client above do not reach the output; the page’s html and head come from the template. That is why many applications start a client directly with <ui:composition ...> and no html element at all, as the specification’s own examples do, which also keeps the file small. The html wrapper above is only there so an editor can validate the markup.

  • A ui:define is optional for every slot. A client that defines nothing still renders: each slot shows its default content, or nothing when it has none.

  • Content sits in the client, scope and EL work as anywhere. Expressions inside a ui:define are evaluated against the client’s view, so #{msg['catalogue.title']} or #{catalogueBean.books} works the same as in a plain page. The EL itself is covered on the Expression Language page.

MyFaces 4.1.4 produced the same markup. In the Development project stage it also appends an empty div with the id jakarta_faces_developmentstage_messages before </body>, a container for development-time messages that Mojarra writes only when it has a message to show.

The template named by template is itself resolved when the view is built. If the path does not exist, the request fails with an error page instead of rendering without the layout: Mojarra reported Invalid path : /WEB-INF/templates/missing.xhtml with the file and column of the ui:composition, and MyFaces reported /WEB-INF/templates/missing.xhtml Not Found in ExternalContext as a Resource. The same holds for a ui:include whose src does not exist.

ui:insert Without a Name

The name attribute of ui:insert is optional. According to the VDL, when no name is given the whole template client is inserted. That makes a template that wraps whatever the client puts inside its ui:composition, with no ui:define at all:

WEB-INF/templates/body-wrap.xhtml, a template with one unnamed slot
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="jakarta.faces.facelets">
<div class="wrap">[<ui:insert/>]</div>
</ui:composition>
unnamed.xhtml, a client that defines no slot
<ui:composition template="/WEB-INF/templates/body-wrap.xhtml"
                xmlns:ui="jakarta.faces.facelets">
  <p>whole body of the client</p>
</ui:composition>

Both implementations answered with <div class="wrap">[, a line break and the client’s paragraph, then ]</div>. Use it for small wrappers (a boxed region, a card) where one slot is enough; as soon as a layout needs two regions, named slots are clearer.

Default Content and Slots

The body of a ui:insert is its default. It is used exactly when the client has no ui:define of that name. This lets a template evolve without breaking its clients: add a new slot with a sensible default and every existing page keeps working; a page opts in by defining it.

<!-- in the template: a slot with a default -->
<ui:insert name="footer">(c) Bookshelf</ui:insert>

<!-- in one client: replace it for this page only -->
<ui:define name="footer">Last updated today</ui:define>

A slot can hold any Facelets content, including components and further ui:insert tags, and defaults are not limited to text. The nav slot above defaults to a link. The same page defined that way rendered Home unchanged until a client defined its own nav.

Two limits to keep in mind. A slot is filled by name only: a template with two inserts of the same name, [<ui:insert name="x">d1</ui:insert>][<ui:insert name="x">d2</ui:insert>], rendered [DEF][DEF] for a client with one <ui:define name="x">DEF</ui:define>, on both implementations, so the definition is copied into every insert of that name. And the definition cannot be partly overridden: a ui:define replaces the whole body of the slot, default included, which is why a template that wants "default plus something" should expose a second, smaller slot instead.

Multi-Level Templates

A template can itself be a template client. A second-level template names the site template with <ui:composition template="...">, fills some of its slots with ui:define, and leaves room for its own clients by putting new ui:insert elements inside those definitions. The Bookshelf uses this for every catalogue page, which share a filter sidebar:

WEB-INF/templates/catalogue-layout.xhtml, a template that is also a client
<ui:composition template="/WEB-INF/templates/layout.xhtml"
                xmlns:ui="jakarta.faces.facelets">
  <ui:define name="title">Catalogue - <ui:insert name="heading">Books</ui:insert></ui:define>
  <ui:define name="content">
    <aside>Filters</aside>
    <section>
      <ui:insert name="main">No books</ui:insert>
    </section>
  </ui:define>
</ui:composition>
fiction.xhtml, a client of the second-level template
<ui:composition template="/WEB-INF/templates/catalogue-layout.xhtml"
                xmlns:ui="jakarta.faces.facelets">
  <ui:define name="heading">Fiction</ui:define>
  <ui:define name="main"><p>Dune</p></ui:define>
  <ui:define name="footer">custom footer</ui:define>
</ui:composition>

The result: the title slot of the site template received Catalogue - Fiction, the content slot received the sidebar and a section holding Dune, and the footer slot was filled with custom footer even though the middle template never mentions it. Slots of the outermost template are therefore reachable from any depth: the client defines footer and it flows through the second level. The slots heading and main exist only in the middle template. A page that defines nothing renders the defaults of every level (Catalogue - Books, No books and (c) Bookshelf).

Keep the chain shallow. Two levels, a site layout and a section layout, covers nearly every application; deeper chains make it hard to tell which file a slot comes from.

Reusing Fragments with ui:include and ui:param

<ui:include src="..."> inserts another Facelets file at that point. It is the right tool for a repeated piece of markup that has no slots of its own, such as one row of the catalogue. The included file is normally a <ui:composition> (or <ui:component>), whose content is what gets included. <ui:param name="..." value="..."/> inside the ui:include passes a variable into it:

WEB-INF/includes/book-line.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="jakarta.faces.facelets">
  <li>#{label}: #{title}</li>
</ui:composition>
The caller
<ul>
  <ui:repeat value="#{['Dune','Emma']}" var="t" varStatus="s">
    <ui:include src="/WEB-INF/includes/book-line.xhtml">
      <ui:param name="label" value="Book #{s.index + 1}"/>
      <ui:param name="title" value="#{t}"/>
    </ui:include>
  </ui:repeat>
</ul>

This rendered <li>Book 1: Dune</li> and <li>Book 2: Emma</li>. A few rules:

  • The src may itself be an EL expression, so a page can include a fragment chosen when the view is built (see Paths, Run-Time Choice and Scope of ui:include). The path is relative to the including file unless it starts with /; use absolute paths from the web application root, as above, so a file can be moved without breaking its includers.

  • A ui:param is an EL variable visible in the included file under its name. It holds the expression, so value="#{t}" stays tied to the loop variable of the enclosing ui:repeat.

  • ui:param also appears inside ui:decorate and ui:composition with a template, to hand the same kind of variables to a template. A template reads them like any other EL variable (see Passing Parameters to a Template).

  • A ui:define inside a ui:include does not give the included file slots. Use ui:decorate with a template for that (ui:decorate and ui:composition). When a fragment needs more than a few parameters or its own validation, a composite component, covered on the Composite Components page, is the better fit, and a reusable tag with attributes is covered on the tag files page.

Paths, Run-Time Choice and Scope of ui:include

Four properties of ui:include were measured on both implementations.

The file is chosen when the view is built. The src of ui:include is an EL expression evaluated by the tag handler, so a condition on a request parameter or on an application-scoped value picks the file once per build:

A fragment chosen from a request parameter
<ui:include src="#{param.frag eq 'b' ? '/WEB-INF/includes/frag-b.xhtml' : '/WEB-INF/includes/frag-a.xhtml'}"/>

/include.xhtml rendered fragment A and /include.xhtml?frag=b rendered fragment B, on Mojarra and MyFaces. Because this is a build-time decision, do not base it on a value that the same request changes (see the build time and render time page).

A relative path is relative to the including file. A file sub/a.xhtml included <ui:include src="b.xhtml"/>, and both sub/b.xhtml and b.xhtml existed in the application root. Both implementations included sub/b.xhtml. The VDL text describes the path as relative to the page that was originally loaded, which is not what happened; write absolute paths and the question does not arise.

A ui:param is visible only inside the include. Next to the loop above, a #{label} written after the ui:include rendered as an empty string, because label exists only for the included file.

No slots in an include. This included file declares a slot:

WEB-INF/includes/with-slots.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="jakarta.faces.facelets">
<p>hello #{who} / extra=[<ui:insert name="extra">no extra</ui:insert>]</p>
</ui:composition>
The caller defines the slot inside ui:include
<ui:include src="/WEB-INF/includes/with-slots.xhtml">
  <ui:param name="who" value="reader"/>
  <ui:define name="extra">EXTRA FROM CALLER</ui:define>
</ui:include>

The parameter arrived (hello reader) but the slot kept its default: extra=[no extra], on both implementations. A fragment with slots is a template, and its caller is a ui:decorate.

ui:decorate and ui:composition

<ui:decorate template="..."> applies a template to a part of a page instead of to a whole page. Unlike ui:composition, it does not discard what surrounds it: the markup around the tag stays, and only the tag’s own content is replaced by the template’s rendering. Its ui:define children fill the template’s slots just as in the page case.

WEB-INF/includes/box.xhtml, a small template
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="jakarta.faces.facelets">
  <div class="box"><h3>#{boxTitle}</h3><ui:insert name="body">empty box</ui:insert></div>
</ui:composition>
Decorating a region of a page
<ui:decorate template="/WEB-INF/includes/box.xhtml">
  <ui:param name="boxTitle" value="Decorated"/>
  <ui:define name="body">inside box</ui:define>
</ui:decorate>

The output was <div class="box"><h3>Decorated</h3>inside box</div>, inside the page’s surrounding markup. The comparison that sticks:

Tag What it does What happens to surrounding markup

ui:composition

Applies a template, or just trims, at the root of a file

Everything outside the tag is discarded

ui:decorate

Applies a template to a region

Everything around the tag is kept

ui:component

Like ui:composition, but also creates a component in the tree (id, binding)

Everything outside the tag is discarded

ui:fragment

Like ui:decorate without a template: creates a component for its content

Everything around the tag is kept

A ui:composition with no template attribute is useful for the files meant to be included, as book-line.xhtml above: only the content of the composition is used, so the file can contain a full html wrapper, or a comment, for the editor’s benefit.

The output of the decorated region was identical on Mojarra and MyFaces. The VDL defines ui:decorate as identical to ui:composition except that it does not discard the content around it.

Passing Parameters to a Template

A template client can pass values to its template with ui:param as a direct child of ui:composition or ui:decorate, next to the ui:define elements. The template reads them as ordinary EL variables, which is the way to give a layout a page title, a section name or a flag without turning them into a slot:

WEB-INF/templates/param-tpl.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="jakarta.faces.html" xmlns:ui="jakarta.faces.facelets">
<h:head><title>#{pageTitle}</title></h:head>
<h:body><h1>#{pageTitle}</h1><ui:insert name="content"/></h:body>
</html>
tplparam.xhtml, a client that passes a parameter
<ui:composition template="/WEB-INF/templates/param-tpl.xhtml"
                xmlns:ui="jakarta.faces.facelets">
  <ui:param name="pageTitle" value="Param title"/>
  <ui:define name="content">content</ui:define>
</ui:composition>

Both implementations produced <title>Param title</title> and <h1>Param title</h1> followed by the content. The value is an expression, not a copy: value="#{catalogueBean.title}" is evaluated each time the template reads pageTitle. Use a ui:param for a small value and a ui:define for markup.

ui:component and the Component Tree

<ui:component> is a ui:composition that also creates a component, and, like ui:composition, it discards everything outside the tag. It is used as the root of an included file when the fragment needs an id, a binding or a rendered condition for its whole content:

WEB-INF/includes/comp.xhtml
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="jakarta.faces.html" xmlns:ui="jakarta.faces.facelets">
discarded before
<ui:component id="cc1"><b>inside component</b></ui:component>
discarded after
</html>

A page that wrote before, <ui:include src="/WEB-INF/includes/comp.xhtml"/>, after and a <ui:fragment id="frag">fragment body</ui:fragment> produced, on both implementations:

before
<b>inside component</b>
after
fragment body

The two differences from the other tags are visible: discarded before and discarded after are gone, and the ui:fragment kept its surroundings. Neither tag renders an element of its own; the component they create is a place in the tree to which id, binding and rendered apply, so rendered="#{...}" on a ui:component is the way to switch off a whole included file at render time. Binding either tag to a bean property follows the rule of every component binding: the bean must be request scoped or narrower.

ui:fragment and ui:repeat

<ui:fragment> wraps a region in a component, so that the region can be given an id, a binding and, most usefully, a rendered condition:

<ui:fragment rendered="#{false}">hidden fragment</ui:fragment>
<ui:fragment rendered="#{true}"><p>shown fragment</p></ui:fragment>

Only the second line reached the output. This is a render-time condition evaluated on every request; contrast it with the tags that decide at view build time, discussed on the page about JSTL tags and build time against render time. The VDL also requires the bean behind a binding on a ui:fragment or ui:component to have a scope no wider than request scope, as for any component.

<ui:repeat> is the template-level loop. It iterates over a List, array, DataModel, Map or other Iterable, exposing each item as var. Its varStatus has the read-only properties index, first, last, even, odd, begin, end and step; over ['a','b','c'] the status read 0/true/false/true, 1/false/false/false and 2/false/true/true for index, first, last and even. There is no count property: asking for #{status.count} gave 0 on Mojarra and a PropertyNotFoundException on MyFaces, so a one-based number is #{status.index + 1}:

<ui:repeat value="#{catalogueBean.books}" var="book" varStatus="status">
  <li class="#{status.even ? 'even' : 'odd'}">#{status.index + 1}. #{book.title}</li>
</ui:repeat>

The attributes begin, end, step, offset and size limit the range, and the implementations disagree on several of them. begin and end are zero-based and end is inclusive. When begin, end or step is not set, the matching status property is an empty string on Mojarra and, on MyFaces, 0, the number of items and 1. The table lists what each implementation rendered for a four-item list a, b, c, d:

Attributes Mojarra 4.1.17 MyFaces 4.1.4

begin="1"

b, c, d

nothing rendered

end="1"

a, b

a, b, c, d (end alone is ignored)

begin="1" end="2"

b, c

b, c

step="2"

a, c

a, c

offset="1"

b, c, d

b, c, d

size="2"

a, b

a, b

offset="1" size="2"

b

b, c

size="9"

error: iteration end index is greater than the number of available rows

error: iteration size cannot be greater than collection size

end="9"

the same error

a, b, c, d

So set begin and end together, treat size as implementation-specific, and never ask for a range larger than the collection. In a range, first is true for the first item rendered and even counts from it: with begin="1" the item b read first=true and even=true on both implementations. The iteration, its rowStatePreserved attribute (documented in the 4.1 VDL and absent from the 4.0 one) and the differences with h:dataTable are covered in depth on the data tables and iteration page.

ui:repeat is a component, not a tag handler: it renders its children once per item and re-evaluates value on each request, so it works with h:inputText and f:ajax inside it, using the item index as a part of the client id. The component tree and the identifiers of repeated components are explained on the architecture page. The tag handler alternative, c:forEach, builds the view once and is a different tool with different consequences, explained on the JSTL page.

ui:remove and ui:debug

<ui:remove> deletes its content at view build time. Nothing inside is rendered, and nothing inside is evaluated: in the scratch application the body was mock text #{nonsense.boom}, an expression that would fail with a property-not-found error if it were evaluated, and the page rendered normally without a trace of it. That makes it the right place for design-time mock content or notes that should not leave the server, unlike an XML comment, which does reach the browser unless FACELETS_SKIP_COMMENTS is set (see the comments section of the Facelets page):

<ui:remove>
  <h:outputText value="mock row: #{nonsense.boom}"/>
</ui:remove>

<ui:debug hotkey="d"/> adds a debugging aid to the page. With the tag present, the rendered page contains a short script that listens for a keyboard shortcut (Ctrl+Shift plus the hotkey letter, d when omitted; the value cannot be an expression) and opens a window that shows the component tree, the scoped variables and the request information of that request. The rendered attribute turns it on and off. The VDL says the tag works only in the Development project stage, but the script was rendered in the Production stage as well on both implementations, so guard it so that it never ships:

<ui:debug hotkey="d" rendered="#{facesContext.application.projectStage == 'Development'}"/>

Use it only in development. In the scratch application the tag with hotkey="x" rendered an inline script that opens the debug window on Ctrl+Shift+X (the script tests the upper-case letter together with the Shift and Control keys). With the guard above the script was present in the Development stage, and an expression comparing the stage with 'Production' removed it, on both implementations. The measurement of the debug window in the Production stage, and the reason to put the guarded tag in the one template that every view uses, are on the project stages page.

f:metadata in a Template

Pages that take view parameters or view actions declare them in f:metadata, which must be a direct child of f:view (see the core tags page and the view parameters page). In an application with a template, the question is where that block lives. The portable answer, run on both implementations, is to put f:view in the template, leave a named slot for the metadata inside it, and let each client fill the slot:

WEB-INF/templates/page.xhtml, f:view with a metadata slot
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:f="jakarta.faces.core"
      xmlns:ui="jakarta.faces.facelets">
<f:view>
  <ui:insert name="metadata"/>
  <h:head><title><ui:insert name="title">Bookshelf</ui:insert></title></h:head>
  <h:body>
    <ui:insert name="content"/>
  </h:body>
</f:view>
</html>
tpl-good.xhtml, a client that supplies its own metadata
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:f="jakarta.faces.core"
                xmlns:ui="jakarta.faces.facelets"
                template="/WEB-INF/templates/page.xhtml">
  <ui:define name="metadata">
    <f:metadata>
      <f:viewParam name="isbn" value="#{detailBean.isbn}"/>
      <f:event type="preRenderView" listener="#{detailBean.load}"/>
    </f:metadata>
  </ui:define>
  <ui:define name="content">
    <p id="out">isbn=#{detailBean.isbn} title=#{detailBean.book.title}</p>
  </ui:define>
</ui:composition>

A request for /tpl-good.xhtml?isbn=978 printed isbn=978 on Mojarra and MyFaces: the view parameter reached the bean and the preRenderView listener ran. Two other placements were tried and are not portable:

  • f:metadata written in the template itself (inside its f:view, with no slot) rendered isbn= on both implementations: the parameter was never read and no error or warning appeared. Every client then shares one fixed block, which is almost never what is wanted.

  • f:metadata inside the content ui:define of a client whose template has no f:view slot for it. Mojarra accepted it and read the parameter (isbn=978). MyFaces 4.1.4 rejected the page with a 500 response whose message was <f:metadata> Parent UIComponent j_id_7 should be instance of UIViewRoot. A page that works on one implementation only is a porting trap, so use the slot inside f:view.

The slot costs nothing for clients that need no metadata: a ui:insert without a definition renders nothing.

Lifecycle Position of Templating

All the ui tags except ui:repeat, ui:fragment, ui:component and ui:debug are tag handlers. They run while the view is built: on the first request (a GET) inside Render Response, and on a postback in Restore View, before any submitted value reaches the model (see the lifecycle page). Four consequences follow.

  • The template of ui:composition and ui:decorate, the src of ui:include and the value of a ui:param are evaluated at build time, from the state of the model before the postback is applied. A ui:include whose src depends on a property that the same request changes is therefore one request late, the same trap as a c:if described on the JSTL page. Anything that must follow the user’s action belongs in rendered.

  • A slot is filled once per build. Which ui:define fills a slot cannot depend on a value that exists only at render time, such as the var of a ui:repeat.

  • The components that the tags create (ui:repeat, ui:fragment, ui:component, ui:debug) have attributes that are evaluated at render time like those of any component: rendered on a ui:fragment is read on every request, in the phases that touch the component.

  • A template and an included file are compiled like any other Facelets file, and an edit takes effect when the compiler checks the file again. The FACELETS_REFRESH_PERIOD parameter and the way its default depends on the project stage are described in the Facelets page.

A subtle point from the specification: a UIComponent tag does not create a second component when one with its id is already in the tree, and it removes a child that is not rendered on this display of the page, as a tag nested in a c:if whose condition turned false. The rule and a measurement are in the Facelets page.

Templates and Fragments in a JAR

A template does not have to be a file of the WAR. Any file under META-INF/resources of a JAR in WEB-INF/lib is served as if it were in the web application root, and template and src can name it with an absolute path. A JAR with META-INF/resources/shared/jar-layout.xhtml:

META-INF/resources/shared/jar-layout.xhtml, inside shared-templates.jar
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="jakarta.faces.facelets">
<div class="from-jar">JAR layout: <ui:insert name="body">no body</ui:insert></div>
</ui:composition>
jar-client.xhtml, a client in the web application
<ui:composition template="/shared/jar-layout.xhtml" xmlns:ui="jakarta.faces.facelets">
  <ui:define name="body">client content</ui:define>
</ui:composition>

The response was <div class="from-jar">JAR layout: client content</div> on Mojarra and MyFaces. A shared module can therefore ship a layout, and the applications that depend on it choose their pages. The price is that the file name becomes part of the module’s contract with its users; give shared templates a prefix directory (shared/ above) so that they do not clash with the application’s own files.

Templates Packaged as Contracts

A template does not have to live in the WAR. A resource library contract is a directory under META-INF/contracts in a JAR (or under contracts in the web application root) that bundles templates, their CSS and scripts. A client names a template of the contract in the usual way, <ui:composition template="/topNav_template.xhtml">, and the runtime looks the file up in the contracts that are active for the view. Replacing the JAR therefore restyles every client without touching their markup, provided the template names and slot names (the contract’s declaration) stay the same. Contracts are the way to ship a theme as a reusable library; for everything inside one application, a plain template under WEB-INF/templates, as above, is simpler. The directory layout, the selection of a contract per view or per URL with f:view contracts or faces-config.xml, the default contract and multi-tenant themes are the subject of the Resource Library Contracts page; the VDL asks for an absolute path in src when the included file comes from a contract.

Mojarra and MyFaces

Everything above was run on both implementations. Where they differ, the page uses the portable form; the differences are:

Topic Mojarra 4.1.17 MyFaces 4.1.4

f:metadata inside a ui:define of a client, with no f:view slot

Accepted, parameter read

500, <f:metadata> Parent UIComponent ... should be instance of UIViewRoot

ui:repeat with begin only, end only, size, offset

Different results, listed in the table of ui:fragment and ui:repeat

Different results, listed in the table of ui:fragment and ui:repeat

Unset varStatus.begin, end, step

Empty strings

0, the item count, 1

varStatus.count

Evaluates to 0

PropertyNotFoundException

Missing template or include file

Invalid path : <path> with file and column

<path> Not Found in ExternalContext as a Resource

Output in the Development stage

No extra markup

An empty div with id jakarta_faces_developmentstage_messages before </body>

ui:debug script

faceletsDebugWindow, wrapped in a span

faceletsDebug, a bare script

Source: the scratch runs described at the top of this page.

What Changed Between Versions

Version Change relevant to templating

JSF 2.0 (2009)

Facelets becomes part of the platform and the standard view declaration language. The ui library of Facelets 1.x is adopted with the same tag names; JSP is deprecated.

JSF 2.2

Resource library contracts, which let a template and its clients come from a contract (specification section 10.1.2); the http://xmlns.jcp.org/jsf/facelets namespace.

Faces 3.0

The javax to jakarta rename. Tag names and attributes are unchanged.

Faces 4.0

The namespace jakarta.faces.facelets replaces the xmlns.jcp.org URI, which is still accepted. JSP views are removed.

Faces 4.1

The VDL of ui:repeat documents rowStatePreserved, which the 4.0 VDL does not list. Templating is otherwise unchanged.

Faces 5.0 (upcoming, milestone 5.0.0-M9)

The milestone page lists a clarification of the ui:repeat attributes such as offset and size (issue 1713), the attributes on which Mojarra and MyFaces differ today, and the removal of the old XML namespaces (issue 2105). It is planned work, not current behaviour.

Nothing else in the ui library changed between 4.0 and 4.1; every example on this page runs unchanged on both. The version history of the project as a whole is on the versions page.

Where Facelets Essentials Is Outdated

Facelets Essentials: Guide to JavaServer Faces View Definition Framework by Bruno Aranda and Zubin Wadia (Apress, 2008) is a short, readable introduction to the same ideas, and its templating chapters are still conceptually right: ui:composition, ui:define, ui:insert, ui:include, ui:param, ui:decorate, ui:fragment, ui:repeat, ui:remove and ui:debug mean what they meant then. What changed is everything around them, because the book describes Facelets 1.x, a standalone open-source library that was added to JSF 1.1 and 1.2 applications in place of JSP:

  • Facelets is now part of Faces. Since JSF 2.0 (2009) Facelets is the standard view declaration language and JSP was deprecated and then removed in Faces 4.0, so nothing is installed. The book’s setup, a FaceletViewHandler registered in faces-config.xml and the facelets.* context parameters in web.xml, is obsolete; the modern parameters are jakarta.faces.FACELETS_* (see the project setup page).

  • The namespace changed twice. Facelets 1.x declared xmlns:ui="http://java.sun.com/jsf/facelets". JSF 2.2 used http://xmlns.jcp.org/jsf/facelets, and Faces 4.0 and later use xmlns:ui="jakarta.faces.facelets" (with jakarta.faces.html and jakarta.faces.core for h and f). The tags keep their names and attributes, so converting an old page is a namespace search and replace.

  • The javax to jakarta rename. Java classes behind binding and component attributes moved from javax.faces to jakarta.faces, and the javax.faces context parameters became jakarta.faces.

  • jsfc has a successor. The book’s jsfc attribute, which turned plain HTML into a component (<input jsfc="h:inputText"/>), is replaced by Faces' passthrough elements, covered on the HTML5-friendly markup page.

  • Newer features the book cannot show: composite components (a better answer to many ui:include plus ui:param uses), resource library contracts, the collection types that ui:repeat accepts today (List, array, ResultSet, Iterable and Map in the 4.1 VDL), and EL 3 and later in templates (see the Expression Language page).

  • The book predates Ajax in Faces. f:ajax (see the Ajax page) can be nested in a template client like any other tag, and ui:repeat and ui:fragment participate in partial rendering through their client ids.

Use the book for the explanation of why templating works the way it does, and this page and the specification for the syntax to type today.

Source: Bruno Aranda and Zubin Wadia, Facelets Essentials (Apress, 2008, ISBN 978-1-4302-1049-8), and Jakarta EE Tutorial: What Is Facelets?

Common Mistakes

  • Content outside ui:composition that never shows. Text or a stray h:outputText placed beside the composition in a client is discarded without a warning. Put it inside a ui:define.

  • A ui:define whose name matches no slot. A typo such as contnet was silently ignored in the scratch run: the real slot kept its default content and no error was logged to the page. Compare the names when a section stays empty.

  • ui:include of a file that is not a composition. The whole file, including its html and head, is inserted and the result is invalid HTML. Make included files ui:composition or ui:component.

  • Using ui:remove to hide secrets. It removes content at build time on the server, so it is safe for that, but a ui:fragment rendered="false" is a runtime decision. Use the one that matches the intent.

  • Deep template chains. Every level adds a file to open to understand one slot. Two levels are usually enough.

  • ui:define inside ui:include. It is ignored: the included file’s ui:insert keeps its default and no error is logged. Use ui:decorate with a template when a fragment needs slots.

  • f:metadata in the wrong place. Inside a template it is silently ignored; inside a content ui:define it works on Mojarra and fails on MyFaces. Use a ui:insert slot inside the template’s f:view (f:metadata in a Template).

  • #{status.count} on ui:repeat. The status has no count: 0 on Mojarra, an exception on MyFaces. Use #{status.index + 1}.

  • A ui:param read outside the include. It is empty there; the variable exists only for the included file or template.

  • Relying on a relative include path. Both implementations resolved it against the including file, which differs from the VDL text. Use absolute paths.

  • A build-time choice that follows the user’s action. The template, src and ui:param values are evaluated when the view is built, before the postback has updated the model. Decide with rendered instead.