?
u
/
p
1-9
The HMPL is a declarative template language designed for server-side UI rendering with client-side interactivity. The language combines:
XMLHttpRequest
.
.hmpl
file extension.
import hmpl from "hmpl-js";
const templateFn = hmpl.compile(
`<div>
<button data-action="increment" id="btn">Click!</button>
<div>Clicks: {{
"src": "/api/clicks",
"after": "click:#btn"
}}</div>
</div>`
);
const clicker = templateFn(({ request: { event } }) => ({
body: JSON.stringify({ action: event.target.getAttribute("data-action") })
})).response;
document.querySelector("#app").append(clicker);
The global hmpl
object serves as the primary interface for
template compilation and request serialization. This object is
automatically available in the global scope without requiring explicit
import.
Method | Type Signature | Description |
---|---|---|
compile |
HMPLCompile | Transforms template strings into executable template functions |
stringify |
(info: HMPLRequestInfo) => string |
Serializes request configuration objects to JSON5 strings |
The compile
method processes
Parameter | Type | Description | Required |
---|---|---|---|
template | string |
|
Yes |
options | HMPLCompileOptions | Compilation configuration parameters | No |
const templateFn = hmpl.compile(
`{
{
"src":"/api/test"
}
}`,
{
memo: true,
autoBody: {
formData: true
},
allowedContentTypes: ["text/html"],
disallowedTags: ["script"],
sanitize: false
}
);
{$config}
).
<div>
<button data-action="increment" id="btn">Click!</button>
<div>Clicks: {{ "src": "/api/clicks", "after": "click:#btn" }}</div>
</div>
Key characteristics:
{}
delimiters
The options
parameter establishes default behaviors for
all requests generated by the compiled template function.
Property | Type | Default | Description |
---|---|---|---|
memo | boolean | false | Enables response caching for identical requests |
autoBody | boolean | HMPLAutoBodyOptions | false | Configures automatic request body generation |
allowedContentTypes | ["text/html"] | Permitted response Content-Type headers | |
sanitize | false | Enables HTML sanitization of server responses | |
disallowedTags | [] | HTML elements to remove from responses |
Note: Request-specific configurations override these defaults when provided.
Serializes HMPLRequestInfo objects into JSON5 strings suitable for template embedding.
const request = hmpl.stringify({
src: "/api/test"
});
const templateFn = hmpl.compile(`{${request}}`);
Implementation notes:
The HMPLTemplateFunction instantiates template executions, managing server requests and DOM updates. Each invocation creates an independent HMPLInstance.
Parameter | Type | Description |
---|---|---|
options |
|
Configuration for request initialization and execution |
const elementObj = templateFn();
// Returns: { response: div, status: 200 }
The HMPLRequestInit interface extends the standard
RequestInit
with
Property | Type | Description |
---|---|---|
mode |
RequestMode | The mode of the request (cors, no-cors, same-origin) |
cache |
RequestCache | The cache mode for the request (default, no-store, reload, etc.) |
redirect |
RequestRedirect | How to handle redirects (follow, error, manual) |
referrerPolicy |
ReferrerPolicy | Policy for the referrer header (no-referrer, same-origin, etc.) |
integrity |
string |
Subresource integrity value for the request |
referrer |
string |
The referrer URL for the request |
get |
HMPLRequestGet | Optional function to retrieve properties from the request |
body |
BodyInit | null |
The body of the request (can be a string, FormData, etc.) |
signal |
AbortSignal | null |
An |
window |
any |
Reference to the window object (if applicable) |
credentials |
RequestCredentials | Credentials mode for the request (omit, same-origin, include) |
headers |
HMPLHeadersInit | Custom headers for the request |
timeout |
number |
Optional timeout duration for the request in milliseconds |
const elementObj = templateFn({
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "text/html"
},
redirect: "follow",
get: (prop, value) => {},
referrerPolicy: "no-referrer",
body: JSON.stringify(data),
signal: new AbortController().signal,
integrity: "...",
window: null,
refferer: "about:client"
});
The get
property specifies a callback function that
executes on property updates within the
Parameter | Type | Description |
---|---|---|
prop | string | The name of the updated property |
value | any | The new property value |
requestObject | HMPLRequest | The associated request object (for multi-request templates) |
const elementObj = templateFn({
get: (prop, value, requestObject) => {
switch (prop) {
case "response":
if (!requestObject) console.log(requestObject);
console.log("Response:");
console.log(value);
break;
case "status":
console.log("Status:");
console.log(value);
break;
}
}
});
get
callback does not trigger for changes to
individual array elements within the requests
property.
This design prevents excessive callbacks during batch updates.
For asynchronous operations, wrap the template function in a Promise:
const val = await new Promise((res, rej) => {
templateFn({
get: (prop, value, requestObject) => {
switch (prop) {
case "response":
if (!value) return;
res(value);
break;
}
}
});
});
The HMPLIdentificationRequestInit interface associates request configurations with specific template requests via unique identifiers.
Property | Type | Description |
---|---|---|
id |
string | number |
Unique identifier matching template request's
initId
|
value |
HMPLRequestInit | HMPLRequestInitFunction | The initialization parameters for the referenced request |
const elementObj = templateFn([
{
id: "1",
value: {
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "text/html"
},
redirect: "follow",
get: (prop, value) => {},
referrerPolicy: "no-referrer",
body: JSON.stringify(data)
}
}]);
When passing an array of initialization objects, requests without
matching initId
values execute with default
configurations. Each template request must explicitly declare its
initId
to receive custom initialization.
The structure of the returned HMPLInstance depends on the template's request configuration:
const templateFn = hmpl.compile(
`{
{
"src":"/api/test"
}
}`
);
const elementObj = templateFn();
Property | Type | Description |
---|---|---|
status | number | HTTP status code of the response |
response | Element | Rendered DOM element |
const templateFn = hmpl.compile(
`<div>
{
{
"src":"/api/test"
}
}
{
{
"src":"/api/test"
}
}
</div>`
);
const elementObj = templateFn();
Property | Type | Description |
---|---|---|
response | Element | Container DOM element |
requests | HMPLRequest[] | Array of individual request results |
Each item in the requests
array contains
status
and response
properties for its
respective request.
The HMPLRequestInitFunction enables dynamic request configuration based on execution context.
Parameter | Type | Description |
---|---|---|
context | HMPLInstanceContext | Execution context containing request information |
const elementObj = templateFn(({
request: { event }
})=>{
return {
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "text/html",
},
redirect: "follow",
get: (prop, value) => {},
referrerPolicy: "no-referrer",
body: new FormatData(event.target, event.submitter),
}
});
Property | Type | Description |
---|---|---|
request | HMPLRequestContext | Contains information about the triggering request |
<div>
<button id="getHTML">Get HTML!</button>
{{ "src":"/api/getHTML", method:"POST", after:"click:#getHTML" }}
</div>
const initFn = (ctx) => {
const event = ctx.request.event;
const text = event.target.textContent;
return {
body: text
};
};
const elementObj = templateFn(initFn);
Request objects define how and when the template makes server requests. These JSON5 objects appear within template markup and support the following properties:
Property | Type | Default | Description |
---|---|---|---|
src |
string |
Required | The source URL of the request |
method |
string |
"GET" | The HTTP method used for the request |
initId |
string | number |
undefined | Identifier for request initialization |
after |
string |
undefined | Event trigger specification |
repeat |
boolean |
true | Whether the request repeats on subsequent triggers |
memo |
boolean |
false | Enables response caching |
allowedContentTypes |
HMPLContentTypes | ["text/html"] | Permitted response Content-Types |
indicators |
HMPLIndicator[] | [] | Status-specific UI indicators |
sanitize |
HMPLSanitize | false | Enables HTML sanitization |
disallowedTags |
HMPLDisallowedTags | [] | HTML elements to remove from responses |
autoBody |
boolean | HMPLAutoBodyOptions
|
false | Configures automatic body generation |
{
{
src: "/api/test",
method: "get",
after: "click:.target",
repeat: true,
indicators: [
{
trigger: "pending",
content: "<p>Loading...</p>"
},
{
trigger: "rejected",
content: "<p>Error</p><button>reload</button>"
}
],
autoBody: {
formData: true
},
sanitize: false,
disallowedTags: ["script", "style", "iframe"],
memo: true,
initId: "id1"
}
}
The src
property specifies the target URL for the request.
This property is required for all request configurations.
Example | Resolution |
---|---|
"src":"http://github.com/api" |
Absolute URL used as-is |
"src":"/api/test" |
Resolved relative to current origin |
The method
property defines the HTTP verb for the request.
Supported methods include:
GET
POST
PUT
PATCH
DELETE
The after
property specifies event-based request triggering
using the format:
${eventType}:${selector}
Event Type | Description |
---|---|
click |
Mouse click events |
submit |
Form submission events |
change |
Input change events |
The repeat
property controls whether a request re-executes
on subsequent trigger events:
true
: Request executes on every trigger (default)false
: Request executes once, then removes listeners
The indicators
property is intended to define the HTML
content that should be rendered in response to a particular request
status. This property enables authors to provide user interface feedback
corresponding to specific states of a request initiated by the
The value of the indicators
property is either a single
HMPLIndicator object or an array of
such objects. Each object specifies a trigger
condition and
associated content
, representing the HTML markup to be
displayed when the corresponding status is active.
The value of the content
property is a string containing
static HTML markup. This markup is not interpreted or extended by the
The trigger
property specifies the status condition under
which the associated content
should be displayed. Its value
may be one of the following:
Property | Type | Description |
---|---|---|
trigger |
HMPLIndicatorTrigger | Condition under which the corresponding content is displayed. |
content |
string |
HTML markup to be rendered in response to the trigger. |
The permissible values for trigger
are:
400
to
599
, indicating client and server errors as defined by
the
HTTP specification.
"pending"
, representing the
Promise
state where a request is in progress and awaiting resolution.
"rejected"
, representing a Promise
rejection or a failed fetch operation.
"error"
, a generic value that serves
as a catch-all trigger, activated under either of the following
circumstances:
400
and
599
.
"rejected"
Promise state."error"
trigger value overlaps with
"rejected"
and any HTTP status codes in the range
400
to 599
. This allows authors to define a
default fallback indicator without the need to enumerate all possible
error conditions individually.
The autoBody
property specifies automatic generation of the
body
property within a HMPLRequestInit object.
Its purpose is to facilitate the automatic population of request bodies
from form-related user input when a request is initiated via
The property accepts either a Boolean value or an HMPLAutoBodyOptions object, determining how the request body should be constructed.
<div>
<form onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form">
<div class="form-example">
<label for="name">Enter your email:</label>
<input type="text" name="email" id="email" required />
</div>
<div class="form-example">
<input type="submit" value="Subscribe!" />
</div>
</form>
{
{
"src":"/api/subscribe",
"after":"submit:#form",
"autoBody":true
}
}
</div>
If the value of autoBody
is true
, the module
automatically generates a FormData
instance using the
associated
SubmitEvent
target element and its submitter.
Value | Behavior |
---|---|
true |
Enables automatic FormData generation using default
behavior.
|
false |
Disables automatic body generation. This is the default behavior. |
HMPLAutoBodyOptions | Enables configuration of specific generation parameters and behaviors. |
When automatic generation is active, the body
property in
the resulting HMPLRequestInit will be assigned a
FormData
instance constructed as follows:
const body = new FormData(event.target, event.submitter);
It is important to note that automatic generation will only overwrite
the existing body
property if the
HMPLRequestInit object is not derived from a RequestInit
function. In such cases, the manually specified body value takes
precedence.
SubmitEvent
originating from
<form>
elements. Future revisions of the input
, progress
, and other interactive
components where automatic body construction is applicable.
The memo
property enables response caching for identical
requests. When enabled:
repeat
is true
The memoization process can be conceptually compared to disabling the
no-cache
directive in the
RequestCache
API, as it prevents repeated fetching of the same resource within the
same runtime environment.
The initId
property establishes an explicit association
between a request and a predefined initialization object. It references
the id
property of a corresponding entry in the
HMPLRequestInit dictionary collection, determining the
initialization parameters for the request.
The value assigned to initId
may be either a
string
or a number
, providing flexibility in
identification schemes.
<div>
{
{
"src": "/api/test",
"initId": "1"
}
}
{
{
"src": "/api/test",
"initId": 2
}
}
</div>
const requestInits = [
{ id: "1", value: ... },
{ id: 2, value: ... },
];
const instance = templateFn(requestInits);
Multiple requests can reference the same initId
, allowing
them to share a common set of initialization options. This behavior is
conceptually analogous to the use of foreign keys in relational
databases, enabling reuse and normalization of request configurations.
The allowedContentTypes
property defines the list of
permissible Content-Type
values within the
headers
of HTTP responses returned from server requests.
This property enables content validation and type safety when processing
server responses.
The property value may be either:
"*"
, indicating that all content types
compatible with the text
method are allowed.
string
values, each representing an
explicitly permitted Content-Type
.
If the array is empty, behavior is equivalent to using
"*"
— all types supporting the text
method are
permitted.
{
{
"allowedContentTypes": [
"application/json; charset=utf-8",
"text/plain"
]
}
}
The default value of this property is ["text/html"]
.
Content-Type
values may lead to uncontrolled application
behavior or vulnerabilities. For instance, receiving a response with
Content-Type: application/octet-stream
could result in the
response body being delivered as raw binary data. In such a case, a
simple message such as Hello, World!
may arrive encoded as:
48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21
For additional guidance on server-side configuration and content type handling, refer to the Server Configuration documentation.
The disallowedTags
property specifies HTML elements to
remove from responses. Supported tags include:
"script"
"style"
"iframe"
The sanitize
property enables DOMPurify-based HTML
sanitization. When enabled:
Extends standard RequestInit with
interface HMPLRequestOptions {
mode?: RequestMode;
cache?: RequestCache;
redirect?: RequestRedirect;
referrerPolicy?: ReferrerPolicy;
integrity?: string;
referrer?: string;
get?: HMPLRequestGet;
body?: BodyInit | null;
signal?: AbortSignal | null;
window?: any;
credentials?: RequestCredentials;
headers?: HMPLHeadersInit;
timeout?: number;
}
Template execution result container.
interface HMPLInstance {
response: undefined | Element | null;
status?: HMPLRequestStatus;
requests?: HMPLRequest[];
}
Provides execution context to request initialization functions.
interface HMPLInstanceContext {
request: HMPLRequestContext;
}
Individual request result container.
interface HMPLRequest {
response: undefined | Element | null | ChildNode[];
status: number;
id?: string;
}
Contains request-specific execution details.
interface HMPLRequestContext {
event?: Event;
}
Property change callback signature.
type HMPLRequestGet = (prop: string, value: any, request?: HMPLRequest) => void;
Template request configuration interface.
interface HMPLRequestInfo {
src: string;
method?: string;
initId?: string | number;
after?: string;
repeat?: boolean;
memo?: boolean;
allowedContentTypes?: HMPLContentTypes;
indicators?: HMPLIndicator[];
sanitize?: HMPLSanitize;
disallowedTags?: HMPLDisallowedTags;
autoBody?: boolean | HMPLAutoBodyOptions;
}
Template compilation function signature.
type HMPLCompile = (
template: string,
options?: HMPLCompileOptions
) => HMPLTemplateFunction;
Template compilation configuration.
interface HMPLCompileOptions {
memo?: boolean;
autoBody?: boolean | HMPLAutoBodyOptions;
allowedContentTypes?: HMPLContentTypes;
sanitize?: HMPLSanitize;
disallowedTags?: HMPLDisallowedTags;
}
Executable template function interface.
type HMPLTemplateFunction = (
options?:
| HMPLIdentificationRequestInit[]
| HMPLRequestInit
| HMPLRequestInitFunction
) => HMPLInstance;
Automatic body generation configuration.
interface HMPLAutoBodyOptions {
formData?: boolean;
}
Union of Promise states and non-success HTTP status codes.
type HMPLInitalStatus =
| "pending"
| "rejected"
| 100
| 101
| 102
| 103
| 300
| 301
| 302
| 303
| 304
| 305
| 306
| 307
| 308
| 400
| 401
| 402
| 403
| 404
| 405
| 406
| 407
| 408
| 409
| 410
| 411
| 412
| 413
| 414
| 415
| 416
| 417
| 418
| 421
| 422
| 423
| 424
| 425
| 426
| 428
| 429
| 431
| 451
| 500
| 501
| 502
| 503
| 504
| 505
| 506
| 507
| 508
| 510
| 511;
Valid indicator display conditions.
type HMPLIndicatorTrigger = HMPLInitalStatus | "error";
Union of all possible HTTP status codes and Promise states.
type HMPLRequestStatus =
| HMPLInitalStatus
| 200
| 201
| 202
| 203
| 204
| 205
| 206
| 207
| 208
| 226;
Content-Type restriction specification.
type HMPLContentTypes = string[] | "*";
HTML elements eligible for removal.
type HMPLDisallowedTag = "script" | "style" | "iframe";
Array of disallowed elements.
type HMPLDisallowedTags = HMPLDisallowedTag[];
HTML sanitization toggle.
type HMPLSanitize = boolean;
Status-specific UI definition.
interface HMPLIndicator {
trigger: HMPLIndicatorTrigger;
content: string;
}
Header dictionary interface.
interface HMPLHeadersInit {
[key: string]: string;
}
Request initialization reference container.
interface HMPLIdentificationRequestInit {
value: HMPLRequestInit | HMPLRequestInitFunction;
id: string | number;
}
Dynamic request initialization signature.
type HMPLRequestInitFunction = (
context: HMPLInstanceContext
) => HMPLRequestInit;