Template System v2.3.6.1
All docs

Javlo2 — Template System

Complete reference for building, configuring, and deploying Javlo2 templates. Covers folder structure, configuration, the HTML→JSP rendering pipeline, dynamic components, image transformation, and the deployment API.

How it works: A Javlo template is a folder containing HTML layouts, SCSS stylesheets, and .properties configuration files. Javlo converts these HTML files into JSP at request time and caches them in a work folder inside the webapp. Committing a template clears that cache and forces a fresh render.

Folder Structure #

Templates live inside the templates directory of a Javlo site context. The minimal required file is config.properties. All other folders are optional but follow a strict naming convention.

my-template/ ├── config.properties # mandatory — template metadata & layout ├── private-config.properties # optional — settings hidden from the editor ├── image-config-base.properties # image transformation rules ├── fonts_reference.properties # web-font declarations │ ├── index.html # default layout (converted to JSP at runtime) ├── home.html # optional homepage-specific layout ├── 404.html # error page layout │ ├── scss/ # stylesheets (SCSS compiled automatically) │ └── main.scss ├── js/ # JavaScript resources ├── img/ # static images bundled with the template │ ├── components/ # DynamicComponent definitions (.properties + .html/.jsp) │ ├── article.properties │ ├── article.html │ └── card.properties │ ├── components-config/ # standard component renderer overrides │ └── page-reference.properties │ ├── macro/ # macros / sub-templates (child templates) ├── mail/ # e-mail templates ├── list/ # static list data files (.properties) ├── resources/ # extra static resources exposed to pages └── i18n/ # translation files (messages_fr.properties, …)
Work folder: At render time Javlo copies the template to /work/<template-name>/<context-key>/ inside the webapp and generates .jsp files from every .html file. Never edit files there directly — they are overwritten on the next commit.

config.properties #

The central configuration file for a template. Every key/value pair controls layout, inheritance, branding, and available features.

my-template/config.properties

Core layout

KeyExampleDescription
htmlindex.htmlMain HTML layout file (default: index.html).
html.homehome.htmlAlternative layout used only for the homepage.
rendererindex.jspGenerated JSP file name (usually auto-derived from html).
area.<name>area.main=main-contentDeclares a content area; value is the HTML id of the target element.
parentbase-templateName of the parent template to inherit from.

Branding & theming

KeyExampleDescription
data.color.primary#1a73e8Brand primary color — substituted as @@color.primary@@ in HTML/SCSS at deploy time.
data.color.secondary#fbbc04Secondary brand color.
data.font.mainRobotoMain font family token.
data.font.headingMontserratHeading font family token.

Column layout (columnable)

KeyExampleDescription
columnable.<area>columnable.main=trueAllows multi-column layout in the given area.
columnable.<area>.defaultcolumnable.main.default=2Default number of columns.
columnable.<area>.maxcolumnable.main.max=4Maximum column count.

Device-specific layouts

KeyExampleDescription
html.mobilemobile.htmlLayout file used when device is detected as mobile.
html.tablettablet.htmlLayout file for tablets.

Template Inheritance #

A template can extend another template via the parent key. The child inherits all layout files, SCSS, component definitions, and image configurations from the parent. Child files with the same name override the parent's.

# child-template/config.properties parent=base-template # Override only the primary color data.color.primary=#e53935

The inheritance chain can be arbitrarily deep. TemplateFactory.getTemplateAllChildren() recursively lists all descendant templates — used by the template.commitAll API action.

Macro templates are lightweight child templates stored in the macro/ sub-folder of their parent. They inherit everything from the parent and are typically used to provide page-type-specific layouts.

HTML → JSP Pipeline #

Javlo never serves raw HTML from a template. On first request (or after a commit), each .html file is processed by XMLManipulationHelper and converted to a .jsp file in the work folder. This conversion:

HTML authoring tip: write plain HTML with Javlo-specific comments and @@token@@ placeholders. Do not include JSP directives yourself — they are added automatically.

Area injection points

Areas are identified by the HTML id attribute declared in config.properties:

<!-- config.properties --> area.main=main-content area.sidebar=sidebar <!-- index.html --> <main id="main-content"> <!-- Javlo injects components here --> </main> <aside id="sidebar"></aside>

Areas #

An area is a named zone inside a layout where editors can place components. Each area corresponds to an HTML element identified by its id.

Declaring areas
config.properties · area.* keys
Each area key maps a logical name (used in the editor) to an HTML element id.
area.header=page-header area.main=main-content area.footer=page-footer

The left side of each area.* key is the area name shown in the editor. The right side is the HTML id of the injection point in the layout.

Component Renderers #

A renderer is a JSP file that controls how a component is displayed on the front end. Renderers can be defined per component type in components-config/, per area, or per device.

components-config/<comp-type>.properties
Renderer configuration
components-config/page-reference.properties
# Named renderers (key starts with "renderer.") renderer.list=/jsp/components/page-reference/list.jsp renderer.cards=/jsp/components/page-reference/cards.jsp renderer.carousel=/jsp/components/page-reference/carousel.jsp # Area-specific override (renderer.name.#areaId#) renderer.cards.sidebar=/jsp/components/page-reference/sidebar_cards.jsp # Default renderer loaded when none is selected default-renderer=list # Available style tokens shown to editors (semicolon-separated) style-list=primary;secondary;light;dark # Do not wrap component in an auto-generated div wrapped=false # Extra JS/CSS loaded when component is on the page resources=/lib/swiper/swiper.min.js,/lib/swiper/swiper.min.css
When wrapped=false, Javlo does not generate a wrapper <div> around the component. You must include the ${previewAttributes}, ${previewCSS}, and ${previewID} variables directly in the root element of your renderer.

JSTL Variables #

The following variables are available in every component renderer JSP:

Generic (all components)

VariableTypeDescription
compIContentVisualComponentThe component instance.
compPagePageBeanThe page the component belongs to.
styleStringStyle selected by the editor.
compidStringComponent unique ID.
valueStringRaw component value.
rendererStringActive renderer name.
previewAttributesStringFull id="…" class="…" attributes for inline editing (use in root element).
previewCSSStringCSS classes combining edit hook and component class.
previewClassStringEdit-mode CSS class only (no component class).
previewIDStringHTML id for inline editing.
cssStyleStringInline CSS style set by the editor.
cssClassStringCSS class set by the editor.
manualCssClassStringManual CSS class added by the editor.
previousSamebooleantrue when the previous component has the same type.
nextSamebooleantrue when the next component has the same type.
editPreviewbooleantrue when in page-preview edit mode.
infoInfoBeanGlobal site info (accessible everywhere). Key property: info.rootTemplateURL — absolute URL of the template folder.

Heading component

VariableDescription
titleHeading text.
depthHeading level (1–6).

Wysiwyg / Paragraph component

VariableDescription
textHTML content with resolved links.

Minimal renderer example

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <!-- wrapped=true (default): Javlo adds the outer div with previewAttributes --> <c:if test="${not empty title}"> <h${depth} class="${cssClass}">${title}</h${depth}> </c:if>
<!-- wrapped=false: you control the root element --> <article id="${previewID}" class="${previewCSS} my-card ${manualCssClass}"> <h2>${title}</h2> <div class="body">${text}</div> </article>

Referencing template static files

<img src="${info.rootTemplateURL}/img/logo.png" alt="Logo"> <link rel="stylesheet" href="${info.rootTemplateURL}/scss/main.css">

Dynamic Components #

A DynamicComponent is a structured data container defined entirely by a .properties file in the components/ folder, paired with an optional HTML or JSP renderer. This is the primary mechanism for custom content types (articles, cards, products, events, …).

components/<type>.properties    +    components/<type>.html
Minimal DynamicComponent definition
components/article.properties
component.type=article component.label=Article component.renderer=components/article.html field.title.type=text field.title.label=Title field.title.order=100 field.body.type=wysiwyg-text field.body.label=Content field.body.order=200 field.image.type=image field.image.label=Illustration field.image.order=300

Component-level properties

KeyDefaultDescription
component.typerequiredUnique identifier matching the file name (e.g. articlecomponents/article.properties).
component.labeltypeHuman-readable name shown in the editor. Add .fr, .de, … variants for multilingual labels.
component.rendererPath to the HTML or JSP renderer, relative to the template root. Can also be component.renderer.mobile for device-specific renderers.
component.wrappedtrueWhether Javlo wraps the rendered output in a <div>.
component.css-classCSS classes added to the wrapper div.
component.prefix / .suffixRaw HTML prepended/appended to the rendered output.
component.column.sizeDefault Bootstrap column width (1, 2, 3, 4, 6, or 12).

Field Types #

Field definition syntax
field.<name>.type=<type> field.<name>.label=Display Label field.<name>.order=100 # sort order (100, 200, …) field.<name>.needed=true # required field field.<name>.i18n=true # translatable per language field.<name>.group=item # grouped for repetition field.<name>.width-edit=6 # editor column width (1-12)

Available field types

TypeDescription & notes
h1 … h6Heading text at the specified level.
textSingle-line plain text.
large-textMulti-line plain text.
wysiwyg-textRich-text editor. Level sub-types: soft, normal, middle, high. Add .innerHtml=true to allow raw HTML.
dateDate picker. Format options: sortableDate, shortDate, mediumDate, fullDate, formatedDate, past, age. Custom pattern: "dd MMMM yyyy".
imageImage upload with optional filter name. Exposes .url, .alt, .viewURL sub-properties.
fileStatic file upload. Exposes .resourceUrl, .previewUrl, .alt, .link.
booleanCheckbox (true/false).
numberNumeric input. Add .min / .max for range constraints; supports range-based search.
colorColor picker. Define palette via list.<name>.
list-oneSingle-value dropdown from a list.* definition.
open-listDropdown combining site content + custom values.
open-multi-listMulti-select open list.
external-linkExternal URL + link title.
internal-linkLink to a page within the site.

Additional field properties

KeyDescription
field.<name>.prefixHTML inserted before the field value.
field.<name>.suffixHTML inserted after the field value.
field.<name>.init-valueDefault value when the component is first created.
field.<name>.min-size / max-sizeMinimum / maximum character count (text fields).
field.<name>.css-classCSS class on the rendered field element.
field.<name>.tagHTML wrapper tag (e.g. p, span).
field.<name>.visibleSet false to hide from the editor UI.
field.<name>.unitUnit label shown next to number fields (e.g. , km).
field.<name>.referenceShow the default-language value as a reference when editing other languages.

Defining static lists

# Static list (key=value pairs) list.category.1=news list.category.1.key=news list.category.2=Blog list.category.2.key=blog # Link a field to the list field.category.type=list-one field.category.list=category # List from a site page path (name=key, title=value) list.topic.path=topics/all

Renderer — HTML syntax for field access

In a .html renderer, access fields using the following expression syntax:

${field.<field-type>.<field-name>.<accessor>}
<!-- field.title.type=text → ${field.text.title.<accessor>} --> <div class="card"> <h2>${field.text.title.XHTMLValue}</h2> <p class="price">€ ${field.number.price.XHTMLValue}</p> ${field.wysiwyg-text.body.XHTMLValue} <img src="${field.image.photo.url}" alt="${field.image.photo.alt}"> <span>${field.text.title.value}</span> <!-- raw stored value --> </div>

Field accessors (JSTL / HTML renderer)

AccessorDescription
.valueRaw stored value — the exact string saved in the component data. Use when you need the unprocessed value (e.g. a date string, a key from a list, or a URL).
.XHTMLValueFully rendered XHTML output (use in HTML renderers). Wraps text in the configured tag, applies prefix/suffix, escapes HTML.
.viewXHTMLCodeRendered XHTML (use in JSP renderers).
.textPlain text value, HTML tags stripped.
.htmlHTML output.
.displayValueFormatted value ready for display (applies date formatting, list label lookup, etc.).
.urlURL (for image, file, external-link fields).
.altAlt text (for image fields).
containerIdID of the component container element (not a field accessor — available directly in the renderer scope).

Embedding config inside the HTML renderer

<!-- Embed list or field config directly in the .html file --> <!--config list.style.1=default list.style.2=featured field.style.list=style -->

Groups & Repetition #

Fields sharing the same group value are repeated together. Editors can add or remove group instances. In the renderer, use start/end comment markers to delimit the repeating block.

Repeating group example — team member list
# components/team.properties component.type=team component.renderer=components/team.html field.name.type=text field.name.order=100 field.name.group=member field.role.type=text field.role.order=110 field.role.group=member field.photo.type=image field.photo.order=120 field.photo.group=member
<!-- components/team.html --> <ul class="team-list"> <!-- start-member --> <li> <img src="${field.image.photo.url}" alt="${field.image.photo.alt}"> <strong>${field.text.name.XHTMLValue}</strong> <span>${field.text.role.XHTMLValue}</span> </li> <!-- end-member --> </ul>

Accessing DynamicComponent data from another page

From a page-reference renderer you can reach a page's DynamicComponent data via:

<!-- Generic access --> ${page.contentAsMap.dynamicComponent.<type>.<field>.<property>} <!-- Example: price prefix from a "destination" component --> ${page.contentAsMap.dynamicComponent.destination.pricePrefix.value} <!-- Access from InfoBean (current page) --> ${info.page.contentAsMap.dynamicComponent.article.body.html}

Component Config Files #

Standard (non-dynamic) component types can be configured through components-config/<comp-type>.properties. This overrides the component's global defaults at the template level.

components-config/<comp-type>.properties
KeyDefaultDescription
renderer.<name>Named renderer JSP path. The editor selects among declared renderers. Optionally append .<areaId> for area-specific override.
default-rendererfirst declaredRenderer loaded when no explicit choice has been made.
style-listSemicolon-separated style names shown to editors (e.g. primary;dark;light).
wrappedtruefalse — component output is rendered as-is; you manage wrapper markup in the JSP.
resourcesComma-separated JS/CSS paths loaded when the component is present on the page.

Page Reference Component #

The page-reference component is the standard way to display lists of pages (news, articles, products, …). Its renderer receives rich JSTL variables for iteration, filtering, and pagination.

JSTL context variables

VariableTypeDescription
pagesCollection<SmartPageBean>Pages selected for display.
titleStringConfigurable title of the component.
linkTitleStringLabel for the "see all" link.
compPageReferenceComponentComponent instance.
paginationPaginationContextPagination state.
tagsCollection<String>Available tags for filtering.
monthsList<String>Available months for filtering.
interactivebooleanAJAX-mode: pages loaded dynamically via jsonUrl.
jsonUrlStringJSON endpoint for interactive mode.

SmartPageBean properties

PropertyDescription
title / htmlTitlePage title (plain / HTML).
descriptionPage meta-description.
urlFull URL of the page.
date / contentDateDateBean — publication / content modification date.
imagesCollection of Image objects (.url, .description, .cssClass).
imagePathPath to the main image.
tags / firstTag / firstTagLabelTag data.
categoryPage category.
authors / creatorAuthor information.
childrenList of child SmartPageBean objects.
realContenttrue when the page has actual content.

PaginationContext properties

PropertyDescription
currentPage / totalPagesCurrent page index and total count.
totalItems / itemsPerPageTotal item count and page size.
hasPrevious / hasNextNavigation flags.
previousUrl / nextUrlURLs for previous/next page.

Example: card list renderer

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <section class="cards-grid ${style} ${manualCssClass}"> <c:if test="${not empty title}"> <h2 class="section-title">${title}</h2> </c:if> <div class="row"> <c:forEach var="page" items="${pages}"> <div class="col"> <a href="${page.url}" class="card"> <c:if test="${fn:length(page.images) > 0}"> <img src="${page.images[0].url}" alt="${page.images[0].description}"> </c:if> <div class="card-body"> <h3>${page.title}</h3> <p>${page.description}</p> </div> </a> </div> </c:forEach> </div> <!-- Pagination --> <c:if test="${pagination.totalPages > 1}"> <nav class="pagination"> <c:if test="${pagination.hasPrevious}"> <a href="${pagination.previousUrl}">&larr; Previous</a> </c:if> <span>${pagination.currentPage} / ${pagination.totalPages}</span> <c:if test="${pagination.hasNext}"> <a href="${pagination.nextUrl}">Next &rarr;</a> </c:if> </nav> </c:if> </section>

Image Configuration #

Image transformation rules are declared in image-config-base.properties (or overridden in config.properties). Each rule is prefixed by a filter name.

my-template/image-config-base.properties
Filter syntax
# Format: [filter].[device].[param] or [filter].[area].[param] # "thumbnail" filter — resize to 300×200 and crop thumbnail.width=300 thumbnail.height=200 thumbnail.crop-resize=true # "hero" filter — full-width, grayscale on mobile hero.width=1920 hero.height=600 hero.mobile.width=768 hero.mobile.grayscale=true

Dimensions

ParameterValueDescription
width / heightpx or -1Target dimensions. -1 = auto (maintain aspect ratio).
max-width / max-heightpx or -1Maximum dimensions; image is never scaled up.
crop-resizetrue/falseCrop image when aspect ratio differs from target.
add-bordertrue/falseAdd letterbox/pillarbox border instead of cropping.
grid-width / grid-heightpxSnap output size to a grid alignment.

Color effects

ParameterValueDescription
grayscaletrue/falseConvert to grayscale (average method).
grayscale-luminositytrue/falseGrayscale using luminosity method.
sepia0–10Sepia toning intensity.
contrast0–1Contrast adjustment (0.5 = no change).
brightness0–1Brightness adjustment.
background-color#rrggbbFill color for transparent areas or borders.
trim-color#rrggbbColor to auto-trim from image edges.

Transform effects

ParameterDescription
round-cornertrue — rounded corners (requires background-color).
horizontal-flip / vertical-flipMirror the image.
web2Reflection effect. Sub-keys: .height (px), .separation (px).
crystallize / glow / emboss / edgeArtistic effects.
bluring-borderBlur the image edges.
layerOverlay another image file on top.
logo-bottom-rightWatermark file placed at the bottom-right corner.
file-extensionForce output format (jpg, png, webp).

Priority resolution order

When a parameter is requested, Javlo resolves it through a cascade:

1. [filter].[area].[device].[param] # most specific 2. [filter].[device].[param] 3. [filter].[area].[param] 4. [filter].[param] # most generic

SCSS / CSS #

Javlo compiles SCSS files automatically. If a .css file is requested but does not exist, Javlo looks for a .scss file with the same base name and compiles it on demand.

After deploying a modified .scss file: delete the corresponding .css file in the work folder to force recompilation. Also delete any .css files that @import the modified file.

Using template tokens in SCSS

/* config.properties declares: data.color.primary=#1a73e8 */ :root { --color-primary: @@color.primary@@; --font-main: @@font.main@@; }

Merging DynamicComponent SCSS

Javlo automatically merges the SCSS of all components/*.scss files into the template's main stylesheet during the import step. Name your SCSS file identically to the .properties file (e.g. components/article.scss).

Internationalisation #

Translation files live in the i18n/ folder and follow the standard Java ResourceBundle naming:

i18n/ ├── messages.properties # default (fallback) ├── messages_fr.properties # French ├── messages_de.properties # German └── messages_nl.properties # Dutch

Access translations in a renderer via JSTL:

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <fmt:message key="nav.readmore" />

To make a DynamicComponent field translatable, add .i18n=true:

field.title.i18n=true # each language stores its own value

Committing a Template #

Committing a template (calling Template.clearRenderer()) clears the work-folder cache and forces Javlo to re-import the template from source on the next request. This is required after any change to HTML, SCSS, properties, or component files.

What happens during a commit

Use template.commitAll to commit a parent template and all its descendants in one operation — useful when a base template change must propagate to child templates.

Template API #

The Remote API exposes three actions for template management. All calls require admin authentication (Bearer token or X-Javlo-Token header).

template.upload POST
Upload a new or updated template as a ZIP archive
Extracts the ZIP into the template folder, then clears the template factory cache. Accepts either a multipart file upload or a URL pointing to a ZIP.

Parameters

ParameterRequiredDescription
actionrequiredMust be template.upload.
namerequiredTarget template name (destination folder).
filemultipartZIP archive uploaded as a multipart form field. Takes priority over url.
urlfallbackURL of a ZIP archive to download and extract.

Response

{ "status": "ok", "data": { "template": "my-template", "uploaded": true } }
template.commit POST
Clear the render cache of a single template
Forces Javlo to re-import the template from source on the next page request.

Parameters

ParameterRequiredDescription
actionrequiredMust be template.commit.
namerequiredTemplate name to commit.

Response

{ "status": "ok", "data": { "template": "my-template", "committed": true } }
template.commitAll POST
Commit a parent template and all its descendants
Recursively commits the named template and every child template that inherits from it.

Parameters

ParameterRequiredDescription
actionrequiredMust be template.commitAll.
namerequiredRoot template name.

Response

{ "status": "ok", "data": { "committed": ["my-template", "my-template/child1", "my-template/child2"], "count": 3 } }

MCP tool names

MCP toolAPI actionDescription
template_uploadtemplate.uploadUpload a ZIP template.
template_committemplate.commitCommit a single template.
template_commitAlltemplate.commitAllCommit a template tree.