0.1.28 • Public • Published


A simple and powerful templating engine that supports:

  • optional chaining
  • file includes (partials)
  • custom processing filters
  • block capture
  • Express support
  • expression evaluation
  • conditional logic
  • nested data sources
  • non-string templates
  • ternary operators
  • looping control flow


$ npm install jnr
var jnr = require('jnr');


Use the render function to apply tags in the template with supplied data.

var result = jnr.render(template, data);

Wrap variable names in {{ double curly brackets }}.



Conditional logic is defined by if, elseif and else tags.

{{if user.logged_in}}
  Log out
  Log in
Log out  


The each ... as tag is used to loop arrays and objects.

{{each pets as pet}}
- {{pet.name}} ${{pet.price}}
- Hamster $25.95
- Guinea Pig $18.80
- Parrot $23.33

Object property names can be accessed by supplying a second property.

{ scores: { Fred: 8, Barney: 4, Wilma: 5 } }
{{each scores as name,score}}
- {{name}} got {{score}}
- Fred got 8
- Barney got 4
- Wilma got 5

Array indexes can be accessed the same way.

{ names: [ 'Fred', 'Barney', 'Wilma' ] }
{{each names as index,name}}
{{index}}) {{name}}
0) Fred
1) Barney
2) Wilma


If the expression is followed by a ? and it is not defined, it will not output and will not throw an error.

Hello {{username?}}

Conditional optional

Optionals can also be used to test conditional statements.

{{if user.cart?}}  
  View cart ({{user.cart.length}})
  Log in to view cart
View cart (5)

Optional chains

Optional variables can be chained using double quotes ??.
If the first expression isn't set the second (and third etc) will be used.

Oh hi {{user.nickname??user.firstname??user.surname}}
Oh hi Marcus

Ternary logic

Ternary operators can be used for shorthand conditional output.

Don't forget your {{weather.isRainy?packItem.rainy:packItem.sunny}}
Don't forget your umbrella

Relational operators

Supported operators inlcude ==,!=,>,>=,<,<=

{{if user.cart.length > 0}}  
  View cart ({{user.cart.length}})
  Cart is empty
Cart is empty


A filter is a function that modifies the data sent to it, filters are separated by the pipe | character.

Filters are applied according to the type of data sent to it. Read more about filters here.

{{cents}} cents is {{cents|$currency}}
1012344 cents is $10,123.44

Separate successive filters with pipe char | and they will be applied in order.


Extra arguments can be supplied to the filter using the following format:




Filtering output

Output blocks can have a filter applied using the filter|%filter_name% tag.

### {{title}}
This is *rendered* as **HTML**.
<p>This is <em>rendered</em> as <strong>HTML</strong>.</p>

Evaluating expressions

Complex expressions are safely resolved using safe-eval library.

Brackets, maths functions, filters, single and double quotes and variable names are all supported.

{price_cents_ex:1848, tax_rate:.1}
Price: {{'$' + Math.round(price_cents_ex*(1+tax_rate))/100 + " inc tax"}}
Price: $20.33 inc tax

Setting variables

Variables can be set using the set tag. Dot syntax is supported.

{{set cart_total=0}}
{{each cart as item}}
  {{set cart_total=cart_total + item.price}}
Total: {{'$' + cart_total}}
Total: $9.08

Capturing blocks

Blocks of the template can be captured to a variable using set %var_name%=...|%filters%.

{{set receipt=...|uppercase}}
  {{set cart_total=0}}
  {{each cart as index,item}}
    {{set cart_total=cart_total + item.price}}
    Item {{index+1}} price is {{'$' + item.price}}
  Total is {{'$' + cart_total}}

TOTAL IS $9.08

Plus equal (+=) assignment is supported, eg. {{set receipt+=...}}.

File includes (partials)

Template data can be loaded from other files efficiently using the syntax {{>filename.ext}}.

First register any directories that contain the content to include:


Then call in the include:


If no extension is used, the default extension .jnr will be assumed.

Sub-directories in the include path are supported.


Filters can be applied to the result.


Included files can include other files if required.

To perform the file operations using async operations, use the renderPromise method.

jnr.renderPromise(tpl, data, options).then(console.log, console.error);

The contents of each file path are stored in memory for future reference by the jnr instance.


Global options can be set for all future renders by overriding the jnr.options property.

jnr.options = {filter:'clean|md', stripWhitespace:true}

Calling jnr.resetOptions() will revert jnr.options back to default settings.

Options can also be custom set for each render by passing in as an argument. These will override the global options.

jnr.render(template, data, {filter:'clean|md', stripWhitespace:'tags'})

Options can also be included as a top level property of the data parameter.

jnr.render(template, {var:'abc', options:{filter:'clean|md', stripWhitespace:'tags'})


Apply global render filter to strings using the option property filter. Will be applied to every string that is rendered.

jnr.render(template, data, {filter:'clean|md'})


This option defines how whitespace will be handled by rendering.

  • 'all' or true Aggressively remove whitespace from all rendered strings using the option property stripWhitespace. This will apply the string filter stripWhitespace after rendering and applying any global filters.
  • 'tags' Remove whitespace created by template tag declarations, will also collapse tabs contained within set,if,else clauses.
  • 'none' or false No changes to whitespace will be made.
jnr.render(template, data, {stripWhitespace:true}) // Same as 'all'
{{if true}}  
there   !

there !


If set to true the render function will return an object with 2 properties:

  • render.result the result of the render
  • render.data a copy of the supplied data object including any set variables

This will allow access to the result of any set declarations that occurred during a render.

{{set inlineMeta=...|yaml}}
men: [John Smith, Bill Jones]
  - Mary Smith
  - {{firstName}} Williams
var result = jnr.render(exp, data, {returnData:true});
Bill Jones

Custom tags

Custom template tags can be defined using jnr.setTags(%opening_tag%,%closing_tag%)


Release history

  • v0.1.28 - Expression sub-rendering bug fix.
  • v0.1.27 - data.options take precedence over options render param, cssmin filter added, docs updated.
  • v0.1.26 - jsmin filter, filters accept curly brace object arguments {foo:bar}. Docs update.
  • v0.1.25 - += assignment support for set.
  • v0.1.24 - Render promise option overwrite bugfix.
  • v0.1.23 - Whitespace tags mode now collapses tabs. Single char var names not rendering bug fix.
  • v0.1.22 - Unresolved includes now throw error, nested include support added.
  • v0.1.20 - Memory cache for file loading, inc express views.
  • v0.1.19 - Express error handling bug fix.
  • v0.1.18 - Includes, promise render, resolving nested expressions. Updated docs and tests.
  • v0.1.17 - Strip whitespace for tags improved.
  • v0.1.16 - Whitespace control added, default options, docs updated.
  • v0.1.15 - Global filters and docs update.
  • v0.1.13 - Filter syntax change to pipes, filter arguments enabled, docs updated.
  • v0.1.12 - Major update, set, set capture blocks, deep eval, documentation update.
  • v0.1.10 - Switched to async file operations
  • v0.1.7 - Improved documentation
  • v0.1.6 - Updated dependencies
  • v0.1.5 - Improved documentation
  • v0.1.4 - registerFilter() added with new datatypes *, arr and obj
  • v0.1.3 - elseif added
  • v0.1.2 - More documentation, added index access [], mixed numeric and constant eval
  • v0.1.1 - Added some basic documentation
  • v0.1.0 - Initial release

Package Sidebar


npm i jnr

Weekly Downloads






Unpacked Size

98.1 kB

Total Files


Last publish


  • loksland