A fully featured HTML view renderer for NodeJS.
npm install hexel-view
- Standard HTML5
- Embedded JavaScript expressions
- Enhanced HTML attributes
- Scope blocks
- Control flow statements
- Partials
- Layouts
- API
Most of the HTML5 specification is supported, with some limitations applied:
- Non-void elements must always have closing tags.
- Only the HTML5 doctype is supported.
- Element attributes must always be quoted using either single or double quotes.
Some additional conveniences have also been added:
- Any element can use the self-closing element syntax:
<element />
The expression will be evaluated, but not output to your template, allowing you to perform operations like you would in Javascript. Only a single expression is allowed.
{% expression %}
These work just like the normal expression, except they will output the return
value of the expression. If the return value is null
or undefined
, then
nothing will be printed.
{%= expression %}
Variables can be defined in your views like you would do in plain Javascript.
You're limited to let
declarations though.
{% let value = expression %}
These expression comments allow you to add comments to your views that won't be printed into the rendered result.
{%# Comment text %}
Element attributes may contain expression statements like any other part of the view.
<element attribute="{%= expression %}">
E.g.
<a href="/items/{%= item.id %}/edit">
You can also bind the value of an attribute to the return value of an expression without needing to use the expression tags in the attribute value.
<element [attribute]="<expression>">
E.g.
<a [href]="showPath">
This syntax allows you to append a value to an attribute value, based on an
expression. If the expression evaluates to a truthy value, then the value after
the dot (.
) will be appended to the base value of the attribute, separated by
a space. The append value may not contain any space characters, to ensure that
it complies with value HTML syntax.
<element [attribute.value]="<expression>">
E.g.
<div [class.is-open]="isOpen">
By using a boolean attribute expression you can add a boolean attribute to an element if the value of its expression evaluated to a truthy value.
<element [?attribute]="<expression>">
E.g.
<input [?checked]="isChecked">
Sometimes it is useful to simply scope some variables in Javascript. You can
achieve this in Hexel by using a plain js
block.
<js>
...
</js>
Print blocks are an alternative syntax to be output expression.
<js @print="<expression>" />
These statements also support block content as an argument in your expressions.
The $block
variable will be injected into your expression as a function which
will return the rendered content of the @print
block. You can also pass arguments
to the $block
function, which will be exposed in the view block.
<js @print="method($block)" @block="arg1, arg2">
...
</js>
The format of the $block
function is:
function $block(...args: unknown[]): Promise<string>;
<js @if="<condition>">
...
</js>
<js @else-if="<condition>">
...
</js>
<js @else>
...
</js>
<js @switch="<expression>">
<js @case="<expression>">
...
</js>
<js @case="<expression>">
...
</js>
<js @default>
...
</js>
</js>
<js @foreach="<value>[, <index>] in <array>">
...
</js>
<js @foreach="<key>[, <value>[, <index>]] in <object>">
...
</js>
<js @while="<condition>">
...
</js>
You can render partial views in other views using the @render
declaration.
<js @render="<partial-view-path>" @context="<expression>" />
Hexel supports layouts and content slots, making composing complex templates much easier.
To define the layout for a view inline, just add an @layout
declaration to the
start of your template.
Note: Partial views cannot define a layout to use inline.
<js @layout="<layout-view-path>" />
Now any content you write in your view will be considered part of the "default" content slot, which can be renderer in the layout view.
You can render the content for the default slot in a layout view using the
@render-content
declaration.
<js @render-content />
You can also specify content for a specific named slot in your view.
<js @content-for="<slot-name>">
...
</js>
To render the content for a named slot, simply add an @render-content
declaration
with the desired slot name. If no content has been rendered for that slot, it won't
output anything.
<js @render-content="<slot-name>" />
<js @if="items.length > 0">
<ul class="list">
<js @foreach="item, index in items">
<li>
<a class="link"
href="/items/{{ item.id }}"
[data-id]="item.id"
[?hidden]="!item.isVisible"
[class.is-active]="index === 0">
{{ item.name }}
</a>
</li>
</js>
</ul>
</js>
<js @else>
<div class="empty">No items</div>
</js>
// ES6 Modules
import { Renderer } from 'hexel-view';
// CommonJS Modules
const { Renderer } = require('hexel-view');
// Default options
let renderer = new Renderer();
// With options
let renderer = new Renderer({
// ...
});
The Renderer
supports various options, which are listed below:
interface RendererOptions {
views?: string = 'views';
cache?: boolean = true;
tags?: {
blockTagName: string = 'js';
expressionStart: string = '{%';
expressionEnd: string = '%}';
printStart: string = '{%=';
commentStart: string = '{%#';
};
layout?: string = null;
tabSize?: number = 4;
}
Hexel integrates seamlessly with ExpressJS. All you have to do is to call the setup method with your express server instance:
renderer.setupExpress(expressApp, {
// ...
});
You can configure the integration using the options listed below:
interface ExpressOptions {
extension?: string = 'html';
isDefault?: boolean = true;
}