Search code examples
jsfxhtmlincludejsf-2facelets

How to include another XHTML in XHTML using JSF 2.0 Facelets?


What is the most correct way to include another XHTML page in an XHTML page? I have been trying different ways, none of them are working.


Solution

  • <ui:include>

    Most basic way is <ui:include>. The included content must be placed inside <ui:composition>.

    Kickoff example of the master page /page.xhtml:

    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
        <h:head>
            <title>Include demo</title>
        </h:head>
        <h:body>
            <h1>Master page</h1>
            <p>Master page blah blah lorem ipsum</p>
            <ui:include src="/WEB-INF/include.xhtml" />
        </h:body>
    </html>
    

    The include page /WEB-INF/include.xhtml (yes, this is the file in its entirety, any tags outside <ui:composition> are unnecessary as they are ignored by Facelets anyway):

    <ui:composition 
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
        <h2>Include page</h2>
        <p>Include page blah blah lorem ipsum</p>
    </ui:composition>
      
    

    This needs to be opened by /page.xhtml. Do note that you don't need to repeat <html>, <h:head> and <h:body> inside the include file as that would otherwise result in invalid HTML.

    You can use a dynamic EL expression in <ui:include src>. See also How to ajax-refresh dynamic include content by navigation menu? (JSF SPA).


    <ui:define>/<ui:insert>

    A more advanced way of including is templating. This includes basically the other way round. The master template page should use <ui:insert> to declare places to insert defined template content. The template client page which is using the master template page should use <ui:define> to define the template content which is to be inserted.

    Master template page /WEB-INF/template.xhtml (as a design hint: the header, menu and footer can in turn even be <ui:include> files):

    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
        <h:head>
            <title><ui:insert name="title">Default title</ui:insert></title>
        </h:head>
        <h:body>
            <div id="header">Header</div>
            <div id="menu">Menu</div>
            <div id="content"><ui:insert name="content">Default content</ui:insert></div>
            <div id="footer">Footer</div>
        </h:body>
    </html>
    

    Template client page /page.xhtml (note the template attribute; also here, this is the file in its entirety):

    <ui:composition template="/WEB-INF/template.xhtml"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    
        <ui:define name="title">
            New page title here
        </ui:define>
    
        <ui:define name="content">
            <h1>New content here</h1>
            <p>Blah blah</p>
        </ui:define>
    </ui:composition>
    

    This needs to be opened by /page.xhtml. If there is no <ui:define>, then the default content inside <ui:insert> will be displayed instead, if any.


    <ui:param>

    You can pass parameters to <ui:include> or <ui:composition template> by <ui:param>.

    <ui:include ...>
        <ui:param name="foo" value="#{bean.foo}" />
    </ui:include>
    
    <ui:composition template="...">
        <ui:param name="foo" value="#{bean.foo}" />
        ...
    </ui:composition >
    

    Inside the include/template file, it'll be available as #{foo}. In case you need to pass "many" parameters to <ui:include>, then you'd better consider registering the include file as a tagfile, so that you can ultimately use it like so <my:tagname foo="#{bean.foo}">. See also When to use <ui:include>, tag files, composite components and/or custom components?

    You can even pass whole beans, methods and parameters via <ui:param>. See also JSF 2: how to pass an action including an argument to be invoked to a Facelets sub view (using ui:include and ui:param)?


    Design hints

    The files which aren't supposed to be publicly accessible by just entering/guessing its URL, need to be placed in /WEB-INF folder, like as the include file and the template file in above example. See also Which XHTML files do I need to put in /WEB-INF and which not?

    There doesn't need to be any markup (HTML code) outside <ui:composition> and <ui:define>. You can put any, but they will be ignored by Facelets. Putting markup in there is only useful for web designers. See also Is there a way to run a JSF page without building the whole project?

    The HTML5 doctype is the recommended doctype these days, "in spite of" that it's a XHTML file. You should see XHTML as a language which allows you to produce HTML output using a XML based tool. See also Is it possible to use JSF+Facelets with HTML 4/5? and JavaServer Faces 2.2 and HTML5 support, why is XHTML still being used.

    CSS/JS/image files can be included as dynamically relocatable/localized/versioned resources. See also How to reference CSS / JS / image resource in Facelets template?

    You can put Facelets files in a reusable JAR file. See also Structure for multiple JSF projects with shared code.

    For real world examples of advanced Facelets templating, check the src/main/webapp folder of Java EE Kickoff App source code and OmniFaces showcase site source code.