Files
hemx/docs/recipes/reusable-partials.md
T
slhx agent d0dc9729fd docs: explain reusable partials
Add the public 'Where are my components?' answer: hemx maps framework component jobs to hemplate partials, generated helpers, app-owned state, IntoEffect composition, and explicit leaf islands. The pre-commit guard now only blocks commits that change REQUIREMENTS.md without an AGENTS.md review, so unrelated follow-up commits are not trapped by old history.

req: canonical_authoring/002

req: canonical_authoring/003
2026-06-12 14:40:25 +02:00

2.0 KiB

Where are my components?

In hemx, the reusable UI unit is a checked hemplate partial plus generated Rust helpers, not a client component instance. You still get reuse and composition; the ownership moves to places Rust apps can inspect and test. req: canonical_authoring/002 req: canonical_authoring/003

Framework component job hemx home
Markup and local UI shape A .heml partial rendered from a Rust view struct.
Props The view struct fields passed into the partial/helper.
Stable child identity h-key on repeated partials, exposed through generated keyed helpers.
Events Real forms, links, handles, and explicit generated events.
State App-owned Rust state, commands/events/projections, or integration-owned stores.
Updating the UI Generated commands such as ui::todo_row.replace(row).
Composition impl IntoEffect: tuples for fixed mixed batches, arrays for fixed repeated batches, and Vec<T: IntoEffect> for dynamic repeated batches.
Client-only widgets Explicit islands or Web Components at leaf boundaries.

A reusable row should be one partial used in both places: initial render and later updates. The handler builds domain state, converts it to a view value, and returns generated commands:

(
    rows
        .into_iter()
        .map(|row| ui::todo_row.replace(row))
        .collect::<Vec<_>>(),
    ui::summary.set(summary),
    ui::notice.set("Saved"),
)

That is the component story: the row partial is reusable; the generated helper knows the target and swap kind; IntoEffect composes the update without a client component runtime, selector lookup, raw ids, raw opcodes, or manual registry plumbing. req: public_api/005

Use an island only when the browser must own high-frequency local behavior, such as a chart, map, editor, or media widget. The island is an explicit leaf; it can emit facts back through generated handles/events, but the app still changes server-owned UI through normal hemx effects. req: interop/003