API Reference

Complete documentation for Template-M. This page covers both Render Mode (the core templating system) and Demo Mode (the interactive demo features).

Render Mode

Render Mode is the core templating system implemented in template-m.js. It transforms JSON data into DOM elements using HTML templates with special attributes.

Functions and Data Objects

Main Functions

templateM(templateId, data, targetElementId)

The main entry point for rendering templates. This function combines template extraction, rendering, and DOM replacement.

templateMRender(templateId, data)

Rendering function that extracts templates and applies data, but does not modify the DOM. Returns a DocumentFragment that can be used programmatically.

This function is used internally by templateM(), but can be called directly when you want the rendered result without automatic DOM replacement.

Template Definitions with data-fn

The data-fn attribute defines extractable template functions within your main template:

<template id="my-template">
  <div>
    <ul>
      <li data-fn="repo:$repos" data-tme="> $name">Item 1</li>
    </ul>
  </div>
</template>

In this example, data-fn="repo:$repos" does two things:

  1. Extracts the <li> element as a template function named "repo"
  2. Creates a slot where $repos will be inserted

Function Prefixes

You can control what becomes part of the function template - whether it includes the element with the data-fn attribute itself or only its children:

<template id="files-template">
  <pre data-tme="> $files"></pre>
  <div data-fn="> file">
    <dt data-tme="> $name"></dt>
    <dd data-tme="> $value"></dd>
  </div>
</template>

With data-fn="> file", the function template is a DocumentFragment containing both the <dt> and <dd> elements, but not the <div> wrapper.

Data Objects and Template Property

Data objects specify which template to use via the template property:

{
  "repos": [
    {"name": "Blueberry", "template": "repo"},
    {"name": "Apple", "template": "repo"}
  ]
}

Automatic Template Naming for Arrays

When a property value is an array, Template-M automatically uses the singular form of the property name as the template name:

{
  "repos": [
    {"name": "Blueberry"},  // uses "repo" template
    {"name": "Apple"}       // uses "repo" template
  ]
}

The property name "repos" becomes "repo" (removes trailing 's'). This automatic singularization only works for simple words ending in 's' - it won't work correctly for irregular plurals like "geese", words ending in "xes" like "boxes", or non-count nouns like "news". For these cases, use explicit template names in your data objects.

Functions Without Slots

When you omit the :$variable part, the function is extracted but no slot is created:

<template>
  <ul>
    <div class="container" data-tme="> $repos"></div>
    <li data-fn="repo" data-tme="> $name">Item 1</li>
  </ul>
</template>

The <li data-fn="repo"> is removed from the template but stored as the "repo" function template. Any data object that specifies "repo" as its template name will use this function.

Multipart Functions

Use slash notation to create a function with multiple parts that are combined into a single DocumentFragment:

<template>
  <div>
    <div data-fn="user/1:$user" data-tme="> $name">name</div>
    <div data-fn="user/2" data-tme="> $alignment">alignment</div>
    <div data-fn="user/3" data-tme="> $age">age</div>
    <div data-fn="user/4" data-tme="> $iq">iq</div>
  </div>
</template>
{
  "user": {
    "name": "Harry",
    "age": 31,
    "iq": 133,
    "alignment": "Chaotic Neutral"
  }
}

All four user/* parts are combined into a single DocumentFragment, creating a layout with four separate <div> elements.

Result:

<div>Harry</div>
<div>Chaotic Neutral</div>
<div>31</div>
<div>133</div>

Accessing Parent Properties

Use $^propertyName to access properties from parent objects:

<template>
  <div>
    <nav data-fn="user:$user">
      <h1 data-tme="> $name"></h1>
      <h1 data-tme="> $^title"></h1>
    </nav>
  </div>
</template>
{
  "title": "Don't look up",
  "user": {"name": "banana"}
}

The $^title refers to the title property in the parent object. Use $^^ for grandparent, $^^^ for great-grandparent, etc.

Result:

<nav>
  <h1>banana</h1>
  <h1>Don't look up</h1>
</nav>

Mixed Templates in Arrays

Objects in an array can specify different templates:

{
  "items": [
    {"name": "Simple Item", "template": "simple"},
    {"name": "Detailed Item", "count": 42, "template": "detailed"},
    {"name": "Another Simple", "template": "simple"}
  ]
}

Element Attributes (data-tme)

The data-tme attribute controls element-level manipulation. It always starts with < (replace element) or > (replace children).

Replace Element (<)

Replace the entire element with data:

<pre data-tme="< $firstName">Default text</pre>
{"firstName": "Victor"}

Result: The <pre> element is replaced with the text "Victor".

Replace Children (>)

Replace the element's children with data:

<h4>header</h4>
<pre data-tme="> $firstName">Default text</pre>
{"firstName": "Victor"}

Result:

<h4>header</h4>
<pre>Victor</pre>

Variable Evaluation

Variables start with $ and refer to properties in the data object:

Conditional Rendering with Comparisons

Use = to compare values and conditionally render:

<template>
  <ul>
    <li data-tme="< $selected=apple">Item Apple</li>
    <li data-tme="< $selected=banana">Item Banana</li>
    <li data-tme="< $selected=cherry">Item Cherry</li>
  </ul>
</template>
{"selected": "banana"}

Result: Only "Item Banana" is shown. Other elements are removed (replaced with empty DocumentFragment).

<ul>
  <li>Item Banana</li>
</ul>

Special Values

When using data-tme="< $variable", the value type matters:

Empty Expressions

When the expression after < or > is empty, the variable evaluates to an empty string which is treated as missing/null, causing the element to be removed:

<span data-tme="<">This element stays</span>
{}

Result: The element is removed (replaced with empty DocumentFragment) because the missing variable evaluates to null.

Multiple Operations

Use semicolons to perform multiple operations:

<span data-tme="< $show1;> $content1"></span>
{"show1": true, "content1": "SURPRISE"}

First checks $show1 (keeps element if true), then replaces children with $content1.

Result:

<span>SURPRISE</span>

Attribute Attributes (data-tma)

The data-tma attribute sets HTML attributes on elements.

Setting a Single Attribute

<input type="text" data-tma="$firstName:placeholder">
{"firstName": "Enter your first name"}

Sets placeholder="Enter your first name" on the input.

Result:

<input type="text" placeholder="Enter your first name">

Setting Multiple Attributes

Use semicolons to set multiple attributes:

<input type="text" data-tma="$firstName:placeholder;$inputStyle:style">
{
  "firstName": "Enter your first name",
  "inputStyle": "border: solid 3px red"
}

Sets both placeholder and style attributes.

Result:

<input type="text" placeholder="Enter your first name" style="border: solid 3px red">

Props Objects

Use a special :props flag to set multiple attributes from an object:

<input type="text" data-tma="$inputProperties">
{
  "inputProperties": {
    ":props": true,
    "placeholder": "Enter your first name",
    "style": "border: solid 3px red"
  }
}

All properties (except those starting with :) are set as attributes.

className Special Handling

The property className is automatically mapped to the class attribute:

<div data-tma="$divProperties">Content</div>
{
  "divProperties": {
    ":props": true,
    "className": "my-class another-class",
    "id": "test-div"
  }
}

Sets class="my-class another-class" and id="test-div".

Toggling Classes with Boolean Values

Use .className syntax to add/remove classes based on boolean values:

<div data-tma="$isFirstActive:.active">Active Item</div>
<div data-tma="$isSecondActive:.active">Inactive Item</div>
{"isFirstActive": true, "isSecondActive": false}

Adds the active class to the first div, removes it from the second.

Result:

<div class="active">Active Item</div>
<div>Inactive Item</div>

Toggling Classes with Comparisons

Compare two values to conditionally add a class:

<li data-fn="repo:$repos" data-tma="$selectedRepo=$name:.test-title" data-tme="> $name"></li>
{
  "repos": [
    {"selectedRepo": "Apple", "name": "Blueberry"},
    {"selectedRepo": "Apple", "name": "Apple"}
  ]
}

The test-title class is added only to the second item where selectedRepo equals name.

Result:

<li>Blueberry</li>
<li class="test-title">Apple</li>

String Interpolation for Event Handlers

Embed variable values in strings for event handlers:

<input type="text" data-tma="console.log($title, $name, $age, $married, $address):onclick">
{
  "title": "Don't look up",
  "name": "John",
  "age": 48,
  "address": null,
  "married": true
}

Sets onclick="console.log(\"Don't look up\", \"John\", 48, true, null)". Variables are JSON-stringified and interpolated.

Syntax Summary

Demo Mode

Demo Mode is an interactive navigation system implemented in template-m-demo.js. It provides tab-based view switching with CSS class management.

Core Concepts

Demo Mode uses CSS classes and data attributes to create an interactive multi-view interface without JavaScript frameworks.

Views and Selectors

View Definition

<div data-tmd-view="users">
  <h2>Users View</h2>
  <!-- content -->
</div>

Defines a view named "users".

Selector Definition

<button data-tmd-selector="users">Show Users</button>

Defines a selector that activates the "users" view when clicked.

Hierarchical Views

Views can be nested. The findTmdMappings() function automatically detects parent-child relationships:

<div data-tmd-view="dashboard">
  <div data-tmd-view="users">
    <!-- nested view -->
  </div>
</div>

JavaScript API

findTmdMappings()

Scans the document and builds a parent-child map of views:

const mapping = findTmdMappings();
// Returns: { "users": "dashboard", "dashboard": "root" }

Used to understand view hierarchy for navigation.

addStyles(tabnames, options)

Dynamically generates CSS to show/hide views or selectors:

addStyles(["home", "users", "settings"], {
  isView: true,
  cssStyles: "display: none",
  complement: false
});

tmdTabClicked(selectorName)

Activates a view and all its parent views:

tmdTabClicked("users");

This sets:

It also recursively activates parent views.

Helper Functions

Usage Pattern

Typical usage involves:

  1. Define views and selectors with data-tmd-* attributes
  2. Call findTmdMappings() to build the hierarchy
  3. Call addStyles() to set up visibility rules
  4. Attach click handlers to selectors that call tmdTabClicked()
// Initialize
window.tmdChildToParent = findTmdMappings();
const viewNames = Object.keys(window.tmdChildToParent);
addStyles(viewNames, {
  isView: true,
  cssStyles: "display: none",
  complement: false
});

// Attach handlers
document.querySelectorAll('[data-tmd-selector]').forEach(el => {
  el.addEventListener('click', () => {
    tmdTabClicked(el.dataset.tmdSelector);
  });
});

Class Naming Convention

Demo Mode uses a specific CSS class naming pattern:

These classes work with the controller attributes to manage visibility and state.

Example: Simple Tab System

<!-- Selectors -->
<div>
  <button data-tmd-selector="home">Home</button>
  <button data-tmd-selector="about">About</button>
</div>

<!-- Views -->
<div>
  <div data-tmd-view="home">
    <h2>Home Content</h2>
  </div>
  <div data-tmd-view="about">
    <h2>About Content</h2>
  </div>
</div>

<script>
// Initialize demo mode
window.tmdChildToParent = findTmdMappings();
addStyles(["home", "about"], {
  isView: true,
  cssStyles: "display: none",
  complement: false
});

// Attach click handlers
document.querySelectorAll('[data-tmd-selector]').forEach(el => {
  el.addEventListener('click', () => {
    tmdTabClicked(el.dataset.tmdSelector);
  });
});

// Show initial view
tmdTabClicked("home");
</script>

Further Resources

For more information: