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