Files
hemx/examples/html_examples/README.md
T
slhx agent 6e6efa0012 test(html-examples): reconcile keyed search rows
Make the active-search example use a safer keyed reconciliation path for filtered rows: remove filtered-out keys, replace retained keys, and append newly visible keys.

req: list/006

req: htmx_equivalents/001

req: examples/001
2026-06-25 18:24:35 +02:00

6.8 KiB

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 reconciles generated keyed partials by removing filtered-out keys, replacing retained keys, and appending newly visible keys. gallery_handlers::search, keyed_filter_effects, 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.