Extend the html_examples gallery README to cover every htmx UI example slug exactly, marking each as implemented, deferred, integration-owned, or refused. Add a test that guards the full slug matrix while keeping the implemented gallery focused on the first CRUD/form/search/load slice. req: htmx_equivalents/001 req: htmx_equivalents/002 req: examples/001
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/002 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
.hemland 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 |
deferred | Should be the same loaded-row resource with a browser-owned visibility trigger; needs a tiny runtime convention or explicit app JS policy before copy/paste. | Not implemented in core gallery yet. |
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 |
integration-owned | This is load-more plus scroll/visibility policy; hemx should not own infinite-scroll state without an app proof. | Use click-to-load until a product slice proves scroll policy. |
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 |
deferred | Needs a real job/progress source and polling or push convention; a fake timer would be a trophy demo. | Later slice should prove server-owned job state. |
value-select |
deferred | Dependent selects are ordinary generated form state, but need a copyable domain example and validation path. | Later slice should add two select resources and server-derived options. |
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 |
deferred | Generated form .clear() already exists; needs a small copyable pattern showing reset after success and preserved values after failure. |
Later slice can add to inline-validation. |
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 Effect::event/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.