Skip to content
TwitterDiscordGitHub

request

The request helper block in the template is used as a declarative point for dynamically updating content based on requests to the server, and getting HTML from there.

PropertyTypeDefaultDescriptionRequired
srcstringThe source URL of the requestYes
methodstring”GET”The HTTP method used for the requestNo
afterstringEvent trigger specificationNo
repeatbooleantrueWhether the request repeats on subsequent triggersNo
intervalnumberOptional interval for repeated requests (in ms)No
indicatorsHMPLIndicator[][]Status-specific UI indicatorsNo
autoBodyboolean | HMPLAutoBodyOptionsfalseConfigures automatic body generationNo
memobooleanfalseEnables response cachingNo
initIdstring | numberIdentifier for request initializationNo
allowedContentTypesHMPLContentTypes[“text/html”]Permitted response Content-TypesNo
disallowedTagsHMPLDisallowedTags[]HTML elements to remove from responsesNo
sanitizeHMPLSanitizefalseEnables HTML sanitizationNo
{{#request
src="/api/test"
method="get"
after="click:.target"
repeat=true
interval=1000
indicators=[
{
trigger: "pending",
content: "<p>Loading...</p>"
},
{
trigger: "rejected",
content: "<p>Error</p><button>reload</button>"
}
]
autoBody={
formData: true
}
memo=true
initId="id1"
allowedContentTypes=["text/html"]
disallowedTags=["script", "style", "iframe"]
sanitize=false
}}{{/request}}

Only indicator block helper.

{{#request src="/api/test"}}
{{#indicator trigger="pending"}}
<span>Loading...</span>
{{/indicator}}
{{#indicator trigger="error"}}
<span>Error</span>
{{/indicator}}
{{/request}}

The src property specifies the target URL for the request.

{{#request src="/api/test"}}
{{/request}}

The method property specifies the HTTP method to be used for the request.

{{#request src="/api/test" method="POST"}}
{{/request}}

The supported methods are GET, POST, PUT, PATCH, DELETE, OPTIONS, TRACE.

The after property defines when to send the request, using the format ${event}:${selectors}. Here, event is the trigger (e.g., click), and selectors specify the target elements.

<div>
<button id="btn">Click!</button>
<div>
Clicks: {{#request src="/api/clicks" after="click:#btn"}}{{/request}}
</div>
</div>

In this example, no request is made to the server until the button is pressed. For such cases, it is better to add another helper block that will be triggered during rendering.

Preview

The repeat property controls whether a request re-executes on subsequent trigger events.

<div>
<button id="btn">Click!</button>
<div>
{{#request src="/api/test" after="click:#btn" repeat=false}}{{/request}}
</div>
</div>
Preview

In the example, we have repeat set to false, which makes repeated requests to the server by clicking on the button impossible.

The interval property specifies the time in milliseconds between consecutive requests to the server, following the JavaScript setInterval timing model.

The interval clearing function is available in the request context.

const templateFn = compile(`
<div>
<button id="btn">Start timer!</button>
<div>
Seconds:
{{#request
src="/api/timer"
after="click:#btn"
interval=1000
repeat=false
}}{{/request}}
</div>
</div>
`);
const el = templateFn({
get: (prop, value, context) => {
const { clearInterval } = context.request;
switch (prop) {
case "response":
if (value?.outerHTML === `<span>10</span>`) {
clearInterval();
}
break;
}
}
});
Preview

In this example we stop the timer when it reaches 10 seconds.

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 HMPL module.

The value is an array of each HMPLIndicator object.

<div>
<button id="btn">Get HTML!</button>
{{#request
src="/api/getHTML"
after="click:#btn"
indicators=[
{
trigger: "pending",
content: "<p>Loading...</p>"
},
{
trigger: "403",
content: "<p>Access error!</p>"
}
]
}}{{/request}}
</div>
Preview

An object describing what specific request status the HTML will be displayed on.

PropertyTypeDescriptionRequired
triggerHMPLIndicatorTriggerThe status that the indicator is showingYes
contentstringThe HTML that is shown when the indicator is activeYes
{{#request
src="/api/getHTML"
indicators= [
{
trigger: "pending",
content: "<p>Loading...</p>"
}
]
}}{{/request}}

The trigger property specifies the status condition under which the associated content should be displayed.

{
trigger: 403;
}

The permissible values for trigger are:

  • HTTP status codes within the range 400 to 599, indicating client and server errors as defined by the HTTP specification.
  • The string literal "pending", representing the Promise state where a request is in progress and awaiting resolution.
  • The string literal "rejected", representing a Promise rejection or a failed fetch operation.
  • The string literal "error", a generic value that serves as a catch-all trigger, activated under either of the following circumstances:
    • A HTTP response with a status code between 400 and 599.
    • A "rejected" Promise state.

The content property must be a plain string containing static HTML markup. This markup is not interpreted or extended by the HMPL module, and therefore does not support HMPL-specific syntax or dynamic bindings.

{
content: "<p>Loading...</p><div>Loading...</div>";
}

Additionally, the value must be a single-line string — line breaks (e.g., \n) or other control characters are not allowed.

The autoBody property specifies automatic generation of the body property within a RequestInit object.

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 example login:</label>
<input type="text"
name="login"
id="login" required />
</div>
<div class="form-example">
<input type="submit" value="Submit!" />
</div>
</form>
{{#request
src="/api/login"
after="submit:#form"
autoBody=true
indicators=[
{
trigger: "pending",
content: "<p>Loading...</p>"
}
]
}}{{/request}}
</div>
Preview

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.

If the value of autoBody is true, the module automatically generates a FormData instance using the associated SubmitEvent target element and its submitter.

{
body: new FormData(event.target, event.submitter);
}

Settings object for each automatic generation

PropertyTypeDescriptionRequired
formDatabooleanAutomatic body generation for form tagNo
{
autoBody: {
formData: true;
}
}

The memo property enables response caching for identical requests. When enabled:

  • Identical requests return cached responses
  • Only active when repeat is true
  • Improves performance for repeated requests
<div>
<button id="btn">Get the square root of 256!</button>
<div>
{{#request src="/api/getSquareRoot" after="click:#btn" memo=true}}{{/request}}
</div>
</div>

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.

memoization

That is, caching means that the DOM tree will not be redrawn if the response from the server is the same.

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 RequestInit dictionary collection, determining the initialization parameters for the request.

const templateFn = compile(`<div>
<button id="btn">Take a component with an API!</button>
{{#request
src="/api/getComponent"
after="click:#btn"
initId=1
indicators=[
{
trigger: "pending",
content: "<p>Loading...</p>"
},
{
trigger: "403",
content: "<p>Access error!</p>"
}
]
}}{{/request}}
</div>`);
templateFn([
{
id: 1,
value: {
credentials: "omit"
}
}
]);
Preview

In this example, initId, if specified, passes RequestInit with credentials with the value "omit", which does not pass credentials to the server, thus access to the API will be limited. If we do not pass initId, then RequestInit will be empty, respectively, all its values will be default for fetch.

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:

  • The string literal "\*", indicating that all content types compatible with the text method are allowed.
  • An array of 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.

{{#request
src="/api/test"
allowedContentTypes=[
"application/json; charset=utf-8"
"text/plain"
]
}}{{/request}}

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.

my-component.html

<script></script>
<div>My component</div>
<iframe></iframe>
<style></style>

index.hmpl

{{#request
src="/api/get-my-component"
disallowedTags=["script", "iframe", "style"]
}}{{/request}}
Preview
<div>My component</div>

The supported methods are script, iframe, style.

The sanitize property enables DOMPurify-based HTML sanitization.

my-component.html

<script></script>
<div>My component</div>

index.hmpl

{{#request
src="/api/get-my-component"
sanitize=true
}}{{/request}}
Preview
<div>My component</div>

Unlike disallowedTags, this is a more serious protection when working with uncontrolled API routes. The function that is used looks like this:

const newResponse = DOMPurify.sanitize(response);