Partials & Fragments
HTMX swaps HTML fragments into the page. StreetJS gives you three ways to produce them.
Named partials
A partial is a template under partials/:
1
2
<!-- src/views/partials/todo-item.html -->
<li id="todo-"></li>
1
2
3
4
5
@Post('/todos')
async add(ctx: StreetContext) {
const todo = await this.todos.create(ctx.body);
ctx.htmx.partial('todo-item', todo); // returns just the <li>
}
With hx-target="#todos" hx-swap="beforeend" on the form, the new <li> appends
to the list — no full reload.
Raw fragments
1
ctx.htmx.fragment(`<span class="badge">${count}</span>`);
Composing lists
Render a partial per item in the controller and inject with }:
1
2
const todos = items.map((t) => ctx.htmx.engine.partial('todo-item', t)).join('');
ctx.htmx.view('home', { todos }); // page has <ul id="todos">}</ul>
HX-* response headers
ctx.htmx.hx({...}) sets HTMX response headers, then chain a render:
1
2
3
ctx.htmx
.hx({ trigger: 'todoAdded', retarget: '#todos', reswap: 'beforeend' })
.partial('todo-item', todo);
Supported: redirect, location, pushUrl, replaceUrl, refresh, retarget,
reswap, reselect, trigger, triggerAfterSettle, triggerAfterSwap. Object
and array triggers are serialized for you.
Detecting HTMX requests
1
if (ctx.htmx.isHtmx) { /* return a fragment */ } else { /* full page */ }
ctx.htmx.view() already does this automatically; use isHtmx for custom branching.
Next: Forms & CSRF.