Files
hemx/docs/hemplate-syntax.md
T
slhx agent b8c83fee25 feat(build): surface structured template diagnostics
Add public .heml syntax authority and refactor the unkeyed generated-target error into structured diagnostic data while preserving the human compiler error.

req: diagnostics/001

req: diagnostics/002
2026-06-12 18:11:39 +02:00

2.3 KiB

.heml syntax surface

.heml files are ordinary HTML plus the small hemplate surface below. Use normal HTML tooling first; hemx/hemplate adds checks for the few template facts that Rust code generation needs. req: diagnostics/001 req: diagnostics/002

Text and HTML

  • {+ expr +} inserts escaped text.
  • {+= expr =+} inserts trusted/rendered HTML. Use it only for values already represented as trusted HTML in Rust.
<h1>{+ self.title +}</h1>
<div>{+= self.body_html =+}</div>

Dynamic attributes

Prefix an HTML attribute with + when its value is a Rust expression.

<a +href="self.url">{+ self.label +}</a>
<button +disabled="self.saving">Save</button>

Dynamic attributes render HTML. They do not replace template facts such as h-key on a loop or data-hemx-slot names used by generated helpers.

Control flow

<section h-if="self.logged_in">Welcome back</section>

<li h-for="todo in &self.todos" h-key="todo.id">
  {+ todo.title +}
</li>

<div h-match="self.state">
  <p h-case="State::Loading">Loading</p>
  <p h-case="State::Ready">Ready</p>
  <p h-case="_">Unknown</p>
</div>

h-key is required when generated targets live inside h-for; it must be the stable template fact on the loop that owns the repeated target. +data-key on a child is just rendered HTML and is not enough for generated keyed helpers.

Generated hemx targets

Generated targets are named in templates and used from Rust through generated helpers. Do not target them with CSS selectors or raw ids in normal app code.

<main data-hemx-root="todos">
  <form data-hemx-form="new_todo" data-hemx-handle="add_todo">
    <input name="title" required>
  </form>

  <p data-hemx-slot="notice">{+ self.notice +}</p>

  <ul>
    <li h-for="row in &self.rows" h-key="row.id" data-hemx-slot="todo_row">
      {+ row.title +}
    </li>
  </ul>
</main>

Rust handlers then use generated helpers such as ui::notice.set("Saved"), ui::todo_row.replace(row), and composed IntoEffect batches. The template owns target names; Rust owns state, commands, events, and projections.

Boundary

This file defines the stable public authoring surface for hemx examples and beginner docs. It does not introduce a client component framework, custom editor framework, JavaScript expression language, selector targeting model, or stored DOM truth.