Files
hemx/examples/html_examples
slhx agent 691c6f009a fix(html-examples): tighten email and progress feedback
Require a complete dotted email before inline validation reports success, preserve the typed email after valid revalidation, and update progress via the actual progress element so visible progress is not stuck at 100%.

req: htmx_equivalents/005

req: examples/001

req: test/006
2026-06-25 16:53:12 +02:00
..

hemx HTML examples

A copy-pasteable pattern gallery for the boring HTML UX patterns popularized by htmx. The point is not to clone htmx attributes; it is to show the hemx idiom: plain .heml, generated resources, server-owned Rust state, keyed partials, and tiny runtime behavior. req: htmx_equivalents/001 req: htmx_equivalents/005 req: examples/001

Run it:

cargo run -p hemx-html-examples

Open http://127.0.0.1:3029.

Pattern matrix

Names match the htmx example URL slug exactly, e.g. modal-custom from https://htmx.org/examples/modal-custom/. Rust resource names use normal identifier spelling only where the language requires it.

Status legend:

  • implemented: copyable .heml and server handlers exist in this example.
  • integration-owned: use hemx generated resources plus app/host/browser policy; do not grow hemx core for the policy.
  • refused: would clone htmx/client framework behavior or a third-party UI kit.
  • deferred: useful, but needs a later vertical slice and proof before becoming a copyable hemx pattern.
htmx example slug Status hemx idiom / boundary Proof anchor
click-to-edit implemented A read view and edit form are the same generated contact_card partial; the server toggles editing and returns gallery::contact_card.replace(...). templates/partials/contact_card.heml, contact_card_handlers::edit_contact, save_contact
bulk-update deferred Same generated-form path as inline validation, but needs a real multi-row selection/write slice so batch semantics are tested instead of claimed. Next slice should add keyed batch rows plus one server-owned bulk command.
click-to-load implemented The server owns the loaded count and returns generated keyed loaded_row replacements plus status text. gallery_handlers::load_more, LoadedRow
delete-row implemented Server state removes the row and returns gallery::editable_row.remove(id). editable_row_handlers::delete_row
edit-row implemented A table row is a keyed .heml partial with generated edit/save forms; no selector target strings. templates/partials/editable_row.heml, editable_row_handlers::edit_row, save_row
lazy-load implemented data-hemx-revealed dispatches a generated form once when visible; the server swaps a generated lazy panel. gallery.heml, gallery_handlers::lazy_load, LazyPanel
inline-validation implemented A generated form reports field failure with validate_email_form.error(...), focuses the field, and updates status text. templates/gallery.heml, gallery_handlers::validate_email
infinite-scroll implemented A revealed sentinel form posts to the same server-owned loading model and replaces generated keyed rows. gallery_handlers::infinite_scroll, data-hemx-revealed, infinite_row
active-search implemented The search form posts a query; the server derives result rows and replaces generated search_result keyed partials. gallery_handlers::search, SearchResult
progress-bar implemented data-hemx-interval ticks a server-owned progress value and replaces a generated progress partial. gallery_handlers::tick_progress, ProgressMeter
value-select implemented The first select posts a generated form; the server derives and replaces generated option rows for the second select. gallery_handlers::choose_category, ValueOption
animations integration-owned CSS transitions are presentation policy around generated replacements; hemx should only preserve stable DOM boundaries. Use keyed partials and app CSS; no core animation framework.
file-upload integration-owned Upload transport, size limits, progress, storage, and security are app/integration policy. Needs product-owned upload route before becoming copyable.
file-upload-input integration-owned Preserving file inputs after errors is browser/security policy; hemx should not fake file state in core effects. Use app-owned upload form policy.
reset-user-input implemented A generated form updates status and returns .clear() after successful submission. gallery_handlers::reset_message
dialogs integration-owned Browser alert/confirm/prompt are app policy; hemx can expose event boundaries but should not own dialog UX. Use native controls or host/app code.
modal-uikit refused Third-party UI kit integration is not a hemx core pattern. Keep as app-owned integration.
modal-bootstrap refused Third-party UI kit integration is not a hemx core pattern. Keep as app-owned integration.
modal-custom deferred A custom modal can be a generated partial plus focus/escape policy, but needs accessibility proof before copy/paste. Later slice should include keyboard/focus tests.
tabs-hateoas deferred Good hemx fit: server-owned selected tab and generated tab panel replacement; needs a focused slice. Later slice should add one tab group.
tabs-javascript refused Client-owned tab state is exactly what generated server-owned state is meant to avoid unless a product needs it. Prefer tabs-hateoas.
keyboard-shortcuts integration-owned Keyboard policy belongs to the app/host; hemx should only receive explicit events. Use generated app-level events / app JS when needed.
sortable integration-owned Drag/drop ordering needs a browser library or pointer policy plus server reorder command. Keep Sortable.js as app-owned integration until proven reusable.
update-other-content implemented Generated effects can update multiple slots from one handler; validation and search already update status plus rows/errors. validate_email, search handlers.
confirm integration-owned Confirmation wording and irreversible-action policy belong to the app; hemx should not own a global confirm system. Use native confirm/app dialog around generated delete forms.
async-auth integration-owned Token refresh/auth sessions belong to auth/session integration, not hemx core. See auth/session recipe boundary.
web-components integration-owned Shadow DOM/custom elements are host integration; hemx can emit events but should not pierce component internals. Use app-owned web component adapters.
move-before refused Experimental DOM preservation API is not a stable hemx contract. Avoid until browser support and a product need make it boring.

Boundary

Implemented rows must remain runnable hemx behavior. Deferred/integration-owned/refused rows are not failures; they prevent a trophy checklist from turning hemx into a client framework. Promote a deferred row only when the slice proves a reusable, boring contract with .heml, generated resources, server-owned state, and tests.