Developer Jahia 8 Jahia 8.1 Jahia 8.2

What are the best practices when creating a new set of page templates in Jahia?

Question

I need to create a new set of page templates for a Jahia project. I want to follow best practices so the templates remain maintainable, reusable, and easy to extend. How should I approach the design, module structure, resource management, and versioning to achieve this?

Answer

In Jahia, there’s no single “correct” way to create a set of templates. Every project has its own constraints and goals. The key is to keep things simple, so the system remains maintainable over time. Complexity should be localized (inside a specific component) rather than applied globally.

Example: for a navigation menu, trying to handle every possible case from the start often results in an unmanageable component. It’s better to start with a menu that meets immediate needs, then enhance it later if required.

Here are some best practices to follow when integrating a new set of templates.


Prepare the static HTML mockup

The integrator usually works from an existing mockup provided by a designer or another team. Before integration, decide:

  • Structural and common parts → template set (layout, header, footer, global areas)
  • Variable and reusable elements → components (blocks, widgets, specific content)

A functional HTML mockup is essential to test rendering before diving into Jahia logic.

Expected structure:

index.html
css/
  reset.css
  custom.css
javascript/
  custom.js
images/
  ...

Minimal example:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Template demo</title>
    <link href="css/reset.css" rel="stylesheet">
    <link href="css/custom.css" rel="stylesheet">
  </head>
  <body>
    <h1>Hello, world!</h1>
    <script src="javascript/custom.js"></script>
  </body>
</html>

Why: separating static design from Jahia integration ensures a clean starting point and clear responsibilities.


Create the Jahia module (including the template set)

Create a minimal module via Maven or the Jahia Studio. This module will contain:

  • Global resources (cssjavascriptimages)
  • JSP files for the templates

Example of simple JSP with areas:

<%@ page language="java" contentType="text/html;charset=UTF-8" %><!doctype html>
<%@ taglib prefix="template" uri="http://www.jahia.org/tags/templateLib" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:set var="language" value="${renderContext.mainResourceLocale.language}"/>
<html lang="${language}">
  <head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>${renderContext.mainResource.node.displayableName}</title>
    <template:addResources type="css" resources="reset.css,custom.css"/>
 </head>
  <body>
    <header>
      <template:area path="header" areaAsSubNode="true" moduleType="absoluteArea" level="0"/>
    </header>

    <main>
      <template:area path="pagecontent" areaAsSubNode="true"/>
    </main>

    <footer>
      <template:area path="footer" areaAsSubNode="true" moduleType="absoluteArea" level="0"/>
    </footer>

    <template:addResources type="javascript" resources="custom.js" targetTag="body"/>
  </body>
</html>

Why: this keeps the base template simple and ensures content areas are clearly defined.


Create reusable definitions (core-component vs project-component)

Separate:

  • core-component: generic definitions and views, reusable in any project.
  • project-component: project-specific definitions.

Core abstractions (mixins + base type)

Create mixins that factorize common fields and a base abstract structure that groups them. Example CND:

[coremix:text] mixin
  - text (string, richtext) i18n
[coremix:image] mixin
  - image (weakreference) < 'jmix:image' mandatory selector='image'

// Base reusable structure: title + text + image
[corent:contentBlock] > jnt:content, mix:title, coremix:text, coremix:image

Why: this avoids duplicating fields across many content types and gives you one place to evolve common behavior.

Inherit in the project (article/blog/author)

Define your project types by inheriting from the base structure. Example CND in the project-component module:

[projectnt:article]   > corent:contentBlock
[projectnt:blogEntry] > corent:contentBlock
[projectnt:author]    > corent:contentBlock
  • All these types share the same properties (jcr:titletextimage), thanks to inheritance.
  • Each type may add extra fields later without breaking existing views (e.g., - jobTitle (string) on author).

Fallback view behavior: if projectnt:author has no specific view, Jahia will use the view defined for corent:contentBlock. You can always introduce a specialized view later (e.g., author.default.jsp) without touching the base.

Resource bundles per type (different labels, same properties)

Even though the technical properties are the same, you can present different labels to editors by scoping labels per content type in your resource bundles.

Example :

# Type labels
projectnt_article=Article
projectnt_blogEntry=Blog entry
projectnt_author=Author

# Field labels for Article
projectnt_article.title=Title
projectnt_article.text=Body
projectnt_article.image=Hero image

# Field labels for Blog entry
projectnt_blogEntry.title=Title
projectnt_blogEntry.text=Excerpt
projectnt_blogEntry.image=Thumbnail

# Field labels for Author
projectnt_author.title=Name
projectnt_author.text=Bio
projectnt_author.image=Photo

Adjust keys to your project’s i18n conventions. The key idea is: same underlying propertiestype‑specific labels.

Why: editors see context‑appropriate labels (e.g., Name/Bio/Photo for an author) without creating new properties or duplicating types.


Handle resource inheritance and overrides

Module priority defines which one overrides the other:

Jahia-Module-Priority: 10

This enables creating a global theme, then overriding it per department or site. For example:

  • core-component: provides default CSS and logic.
  • project-component: overrides CSS to fit the project brand.
  • template-set: adds layout-specific CSS.
  • theme-x: overrides visuals for a specific department.

Why: this layered approach avoids code duplication, lets you maintain a single base style, and adapt visuals without touching core logic.


Use views and fragments

Splitting a template into fragments improves maintainability.

<template:module node="${currentNode}" view="hidden.head" />

Views prefixed with hidden. are not available directly in the editor.

Why: fragments reduce duplication and ensure some views are only used programmatically, which avoids accidental misuse by editors.


Additional best practices

Unique IDs using UUID:

<a name="button_${currentNode.identifier}">${title}</a>

Why: guarantees each HTML ID is unique and valid, avoiding DOM conflicts, especially when the same component type is used multiple times on a page.

Example of a generic view with an image: This is just one example, here using an image property. You can adapt the same approach for other types of fields.

File: /src/main/resources/coremix_image/html/image.image.jsp

<%@ page language="java" contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="template" uri="http://www.jahia.org/tags/templateLib" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="jcr" uri="http://www.jahia.org/tags/jcr" %>
<c:set var="imageNode" value="${currentNode.properties.image.node}"/>
<c:if test="${! empty imageNode}">
    <c:url var="imageUrl" value="${imageNode.url}" context="/"/>
    <c:set var="alt" value="${imageNode.displayableName}"/>
    <img src="${imageUrl}" alt="${fn:escapeXml(alt)}" />
</c:if>

To include this view from any JSP:

<template:include view="image"/>

Why: centralizing rendering logic in a shared view ensures consistent markup, proper accessibility attributes, and easy reuse across multiple node types.

Complete default resource bundle  file: having a full default language file ensures that if a translation is missing in another language, the user still sees meaningful labels instead of empty strings.


Versioning and Maven multi-module project

For development: x.y.z-SNAPSHOT.

For production: stable releases.

Grouping modules in a parent Maven project simplifies dependency and version management.

This ensures a consistent deployment process, easy rollbacks, and cleaner collaboration between developers.