@ivi/htm
v3.0.2
Published
ivi HTML-like markup language.
Downloads
7
Readme
ivi HTML Template Language
@ivi/htm
module provides an interface for creating ivi templates with
template literals:
htm
creates a template with HTMLElement nodes.svg
creates a template with SVGElement nodes.
htm`
<div id="app">
<h1>Template Example</h1>
<div class="content">
${condition ? "true" : "false"}
</div>
</div>
`;
Multiple Root Nodes
htm`
<div></div>
${expr}
text
<div></div>
`
Childless elements can be self closed with a />
syntax
htm`
<div
class="a"
/>
`;
Whitespaces
- Whitespaces around newlines are removed:
<div>
<p></p>
ab
<p></p>
</div>
<div><p></p>ab<p></p></div>
- Inline whitespaces are collapsed into one whitespace:
<div> <span> a b </span> </div>
<div> <span> a b </span> </div>
- Whitespaces around newlines in text nodes are collapsed into one whitespace:
<div>
ab
cd
</div>
<div>ab cd</div>
- Vertical tab
\v
character prevents from removing all whitespaces around newlines:
<div>
<b>1</b>
\v item left
<div>
<div><b>1</b> item left</div>
Element Attributes Syntax
HTML Template Language supports additional syntax to work with DOM properties, events, etc.
<div name="value" />
- Static attribute.<div name />
- Static attribute.<div name=${expr} />
- Dynamic attributeelement.setAttribute(name, expr)
.<div .name=${expr} />
- Propertyelement[name] = expr
.<div *name=${expr} />
- Propertyelement[name] = expr
, diffs against a DOM value.<div ~name="value" />
- Static style<div style="name:value;">
.<div ~name=${expr} />
- Dynamic styleelement.style.setProperty(name, expr)
.<div @name=${expr} />
- Eventelement.addEventListener(name, expr)
.<div ${directive} />
- Client-Side Element Directivedirective(element)
.<div &=${directive} />
- Client-Side Element Directivedirective(element)
.<div &:ssr=${directive} />
- Element Directive that works during Client-Side and Server-Side Renderingdirective(element, hydrate)
.<div .textContent=${expr} />
- Text content.
Attributes
<div name="value" />
- Static attribute with a value<div name="value">
.<div name />
- Static attribute without a value<div name>
.<div name=${expr} />
- Dynamic attributeelement.setAttribute(name, expr)
.
DOM attributes are assigned with Element.setAttribute(..)
.
When dynamic attribute has an undefined
, null
or false
value, it will be removed from the DOM element with Element.removeAttribute(..)
method.
Properties
<div .name=${expr} />
- Propertyelement[name] = expr
.<div *name=${expr} />
- Propertyelement[name] = expr
, diffs against a DOM value.
Properties are assigned with an assignment operator Element.name = value
.
Diffing with a DOM value is useful in use cases when we use <input>
values to avoid triggering unnecessary input
events.
Styles
<div ~name="value" />
- Static style<div style="value">
.<div ~name=${expr} />
- Dynamic styleelement.style.setProperty(name, expr)
.
Static styles are automatically merged with :style="value"
attribute.
Dynamic styles are assigned with a CSSStyleDeclaration.setProperty(..)
method.
When style has an undefined
, null
or false
value, it will be removed with CSSStyleDeclaration.removeProperty(..)
method.
Events
<div @name=${expr} />
- Eventelement.addEventListener(name, expr)
.
Events are assigned with an EventTarget.addEventListener(..)
method.
When event has an undefined
, null
or false
value, it will be removed with EventTarget.removeEventListener(..)
method.
Directives
<div ${directive} />
- Client-Side Element Directivedirective(element)
.<div &=${directive} />
- Client-Side Element Directivedirective(element)
.<div &:ssr=${directive} />
- Element Directive that works during Client-Side and Server-Side Renderingdirective(element, hydrate)
.
Directive is a function that is invoked each time template is updated and receives a DOM element associated with a directive:
type ElementDirective = <E extends Element>(
element: E,
hydrate?: boolean,
) => void | string | { a?: string, c?: string; };
Directive function is invoked only when template is created with a different function, so if we are going to reuse the same function, it can be used as a DOM element created callback:
const Example = component((c) => {
const onCreated = (innerElement) => {
// ..
};
return () => htm`
<div>
<div class="Inner" ${onCreated} />
</div>
`;
});
Directives can be used not just as a simple DOM created callbacks, but also as stateful directives. E.g.
function createStatefulDirective() {
// Internal state that stores previous value.
let prev;
// Returns a factory that creates directive functions.
return (next) => (element) => {
// Check if previous value has been changed.
if (prev !== next) {
prev = next;
// Updates textContent only when input value is changed.
element.textContent = next;
}
};
}
const Example = component((c) => {
const directive = createStatefulDirective();
return (i) => htm`
<div ${directive(i)} />
`;
});
Text Content
<div .textContent=${expr} />
- Text Contentelement.textContent = expr
.
Text content property can be used as an optimization that slightly reduces memory consumption for elements with a text child. It will create a text node with a Node.textContent
property and won't have any stateful nodes associated with a text node.
Text content value should have an undefined
, null
, false
, string
or a number
type.