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.