npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

jtdal

v5.0.1

Published

Small template engine based on Zope TAL, using data attributes

Downloads

29

Readme

<div>
  Hello there, <span data-tdal-replace="name">world</span>
</div>
{
  "name": "General Kenobi"
}

jTDAL

Template Attribute Language for JavaScript

npm License GZipped size

Small template engine based on Zope TAL, using data attributes.

Written in TypeScript, for Node.js and the browser.

  • 🏝️ 0 dependencies
  • 🪶 Only ~2.7KB gzipped!
  • ⚡️ Written in TypeScript
  • 🎨 Designer-friendly
    • Templates work in any WYSIWYG editor or browser preview
    • No special syntax to break HTML validation
  • 🚀 Compile templates

Why another template engine?

Because I didn't find a fast JavaScript template engine based on attributes. While Mustache is absolutely awesome, I find its syntax quite weird. Using attributes, the page can be designed with any WYSIWYG editor or previewed in the browser without the need for the actual rendering data.

Installation and Usage

You can use jTDAL directly in the browser or as an npm package.

Browser

<script type="module">
    import jTDAL from 'https://unpkg.com/jtdal/jTDAL.min.js';
    
    const templateEngine = new jTDAL( );
    
    // Define a macro that contains a dynamic element
    templateEngine.MacroAdd( 'macrofoo', '<span data-tdal-content="foo"></span>, ' );

    // Template that uses the macro with replace AND adds another element
    const template = `<span data-tdal-replace="MACRO:macrofoo"></span><span data-tdal-content="bar"></span>`;
    
    const t = templateEngine.CompileToFunction(template);
    const data = { foo: "Hello", bar: "World" };
    const result = t(data);
    
    document.getElementById( 'result' ).innerHTML = result;
    // Output: Hello, World
</script>

Node.js

Install jTDAL via npm:

npm install jtdal

Then use it in your project:

import jTDAL from 'jtdal';

// Create template engine
const templateEngine = new jTDAL( );

// Add a macro that contains a dynamic element
templateEngine.MacroAdd( 'macrofoo', '<span data-tdal-content="foo"></span>, ' );

// Template that uses the macro with replace AND adds another element
const template = `<span data-tdal-replace="MACRO:macrofoo"></span><span data-tdal-content="bar"></span>`;

const t = templateEngine.CompileToFunction(template);
const data = { foo: "Hello", bar: "World" };
const result = t(data);

console.log(result);
// Output: Hello, World

Constructor

Constructor takes 2 parameters that controls trim and strip behaviour:

constructor( trim = true, strip = true )

Methods

CompileToFunction(template)

Compile the template returning a callable function with an optional parameter data.

CompileToString(template)

Compile the template returning a string containing the function code. Usefull to precompile templates and save as javascript files.

Template language documentation

Path Expressions

A path expression indicates the position of the value in the data object. Given the following data:

data = { foo: "bar", foobar: { bar: "foo" } };
  • foobar/bar resolves to foo
  • foo resolves to bar

The syntax of a path expression is:

path/nonexistent | existing/path | never/reached

The first existing and truthy path is used as the result. If no paths match, false is returned.

Truthy/Falsy evaluation:

  • Falsy values: false, null, undefined, "" (empty string), 0, [] (empty array), {} (empty object)
  • Everything else is considered truthy

Modifiers

  • Booleans: Prefix with ! for negation.
  • Strings: Prepend STRING: to define static strings or templates with placeholders.

Special keywords:

  • TRUE: Always returns true (halts parsing)
  • FALSE: Always returns false (halts parsing)
  • GLOBAL: search directly in the global context bypassing other contexts (es. GLOBAL/variableName)
  • REPEAT: search directly in the repeat context bypassing other contexts (es. REPEAT/variableName)

Strings

A string is a path prefixed with STRING:. It can contain placeholders in the form {path-expression|another-path|last-path-but-not-a-string}. The placeholders are replaced with the value of the path expression. In strings is possible to use {?condition} or {?!condition} for conditional inclusions. Each {?condition} must be closed with a {?/condition}. Same for {?!condition}.

STRING:This is a string with a {foo}{?bar} and a {bar}{/bar} placeholder.

Attributes

The engine supports the following data- attributes. These attributes are resolved in the specified order:

  1. data-tdal-condition="path-expression-boolean-mod-allowed"

  2. data-tdal-repeat="variable-name path-expression"

  3. data-tdal-content="path-expression-string/macro-allowed

  4. data-tdal-replace="path-expression-string/macro-allowed"

  5. data-tdal-attributes="attribute path-expression-string-allowed[;;attribute path-expression-string-allowed]"

    • For boolean flag attributes, append ? to the attribute name: attribute? path-expression
  6. data-tdal-omittag="path-expression-boolean-mod-allowed"

In the documentation below, the attributes are described in the following order for better understanding:

  1. Omittag
  2. Attributes
  3. Content
  4. Replace
  5. Condition
  6. Repeat

Attribute Details

Omittag

Removes the tag while keeping its content if the path expression evaluates to true.

Examples:

<!-- Always remove the tag -->
<span data-tdal-omittag="TRUE">Content</span>
<!-- Result: Content -->

<!-- Never remove the tag -->
<span data-tdal-omittag="FALSE">Content</span>
<!-- Result: <span>Content</span> -->

<!-- Remove tag if variable is truthy -->
<span data-tdal-omittag="hideWrapper">Content</span>

<!-- Remove tag if variable is falsy -->
<span data-tdal-omittag="!showWrapper">Content</span>

<!-- Remove tag based on nested path -->
<span data-tdal-omittag="config/removeWrappers">Content</span>

Attributes

Adds or modifies multiple attributes based on the path expression. Each attribute-value pair is separated by ;;. Existing attribute values are preserved if the expression evaluates to true.

Boolean Flag Attributes: If an attribute name ends with ?, it will be added as a boolean attribute (without value) when truthy, or removed when falsy.

Examples:

<!-- Keep existing attribute value -->
<img src="default.jpg" data-tdal-attributes="src TRUE" />

<!-- Replace with dynamic value -->
<a href="#" data-tdal-attributes="href user/profileUrl">Profile</a>

<!-- Use string template -->
<img src="default.jpg" data-tdal-attributes="src STRING:https://example.com/images/{imageId}.jpg" />

<!-- Remove attribute -->
<input type="text" disabled data-tdal-attributes="disabled FALSE" />

<!-- Boolean flag attributes (HTML5 boolean attributes) -->
<input type="checkbox" data-tdal-attributes="checked? isChecked" />
<button data-tdal-attributes="disabled? !canSubmit">Submit</button>
<option data-tdal-attributes="selected? isDefault | FALSE">Default</option>

<!-- Multiple attributes including flags -->
<input data-tdal-attributes="type STRING:checkbox;;checked? user/preferences/newsletter;;disabled? !isEditable" />

<!-- Multiple attributes -->
<a data-tdal-attributes="href link/url;;class STRING:btn btn-{type};;title link/description">Link</a>

<!-- Fallback to keeping existing value -->
<img src="default.jpg" data-tdal-attributes="src dynamicUrl | TRUE" />

Content

Replaces the tag's content with the result of the path expression. If the expression is false, the content is removed.

Examples:

<!-- Simple content replacement -->
<span data-tdal-content="username">Default username</span>

<!-- With HTML structure (not escaped) -->
<div data-tdal-content="structure richTextContent">Default content</div>

<!-- String template -->
<h1 data-tdal-content="STRING:Welcome, {user/name}!">Welcome!</h1>

<!-- Conditional content -->
<div data-tdal-content="errorMessage | STRING:No errors">Error placeholder</div>

<!-- Using macro -->
<div data-tdal-content="MACRO:userCard">User info</div>

Replace

Replaces the tag and its contents with the result of the path expression. If the expression is false, the tag and its contents are removed.

Examples:

<!-- Replace entire element with value -->
<div data-tdal-replace="statusMessage">Status placeholder</div>

<!-- Replace with HTML (not escaped) -->
<div data-tdal-replace="structure htmlContent">Placeholder</div>

<!-- String template replacement -->
<span data-tdal-replace="STRING:<strong>{username}</strong>">Username</span>

<!-- Using macro -->
<div data-tdal-replace="MACRO:navigationMenu">Nav placeholder</div>

Condition

Removes the tag and its contents if the path expression evaluates to false.

Examples:

<!-- Show if variable is truthy -->
<div data-tdal-condition="isLoggedIn">Welcome back!</div>

<!-- Show if variable is falsy -->
<div data-tdal-condition="!isGuest">Member content</div>

<!-- Always show -->
<div data-tdal-condition="TRUE">Always visible</div>

<!-- Never show -->
<div data-tdal-condition="FALSE">Never visible</div>

<!-- Check nested path -->
<div data-tdal-condition="user/permissions/canEdit">Edit button</div>

<!-- With fallback -->
<div data-tdal-condition="feature/enabled | config/defaultEnabled">Feature content</div>

Repeat

Repeats the tag for each element in an array or object. While iterating, a REPEAT object and the loop variable are available.

Examples:

<!-- Simple array iteration -->
<ul>
  <li data-tdal-repeat="item items" data-tdal-content="item">Item</li>
</ul>

<!-- Object iteration with properties -->
<div data-tdal-repeat="user users">
  <h3 data-tdal-content="user/name">Name</h3>
  <p data-tdal-content="user/email">Email</p>
</div>

<!-- Using REPEAT variables -->
<tr data-tdal-repeat="row data" data-tdal-attributes="class STRING:{?REPEAT/row/odd}odd{?/REPEAT/row/odd}{?REPEAT/row/even}even{?/REPEAT/row/even}">
  <td data-tdal-content="REPEAT/row/number">Index</td>
  <td data-tdal-content="row/value">Value</td>
</tr>

<!-- Nested repeats -->
<div data-tdal-repeat="category categories">
  <h2 data-tdal-content="category/name">Category</h2>
  <ul>
    <li data-tdal-repeat="product category/products" data-tdal-content="product/name">Product</li>
  </ul>
</div>

The REPEAT object provides:

  • index: Current index (or key for objects)
  • number: Current iteration, starting from 1
  • even, odd: Boolean flags for even/odd iterations
  • first, last: Boolean flags for the first/last element
  • length: Total items in the array or keys in the object

Macros

jTDAL support macros (equivalent of TAL's METAL or partials in Mustache) in content and replace.

First you need to add your macro to the template:

const macro = `Hello, <span data-tdal-replace="name|STRING:World"></span>!`;
templateEngine.MacroAdd( "helloworld", macro );

Then you can call it from the template:

Content

<span data-tdal-content="MACRO:helloworld">Something</span>
<span data-tdal-content="structure MACRO:helloworld">Something</span>

Replaces the tag's content with the template foo

Replace

<div data-tdal-replace="MACRO:helloworld">Replaced content</div>
<div data-tdal-replace="structure MACRO:helloworld">Replaced content</div>

Replaces the tag with the template foo