Research: how far htmx and the existing filter.js carry a filterable Series list #123

Closed
opened 2026-08-17 15:22:46 +07:00 by sulthan · 3 comments
Owner

Part of #114

Question

Can the Series list's filtering, sorting, and paging be built with what the frontend already
has, or does it need something new?

In tree: backend/internal/web/static/htmx.min.js and static/filter.js, plus the existing
htmx patterns in templates/ — hx-get/hx-trigger every 30s/hx-swap outerHTML for the Lanes
fragment, and hx-post with hx-target="#readers" for roster actions.

Report:

  • What static/filter.js actually does today and whether it is client-side over a rendered list
    or driven by the server.
  • Which of the Series list's needs (URL-addressable filters, sort, paging, a search box, a
    per-row action that re-renders one row rather than the whole list) htmx covers idiomatically,
    and which it does not.
  • Whether server-rendered filtering keeps the URLs the IA ticket wants bookmarkable, given htmx
    swaps do not change the address bar without hx-push-url.
  • Any dependency this would imply, with the reminder that stdlib and already-present code come
    first and a new module needs a stated reason.

Facts and file citations only; the decisions belong to the tickets that consume this.

Part of #114 ## Question Can the Series list's filtering, sorting, and paging be built with what the frontend already has, or does it need something new? In tree: `backend/internal/web/static/htmx.min.js` and `static/filter.js`, plus the existing htmx patterns in `templates/` — `hx-get`/`hx-trigger every 30s`/`hx-swap outerHTML` for the Lanes fragment, and `hx-post` with `hx-target="#readers"` for roster actions. Report: - What `static/filter.js` actually does today and whether it is client-side over a rendered list or driven by the server. - Which of the Series list's needs (URL-addressable filters, sort, paging, a search box, a per-row action that re-renders one row rather than the whole list) htmx covers idiomatically, and which it does not. - Whether server-rendered filtering keeps the URLs the IA ticket wants bookmarkable, given htmx swaps do not change the address bar without `hx-push-url`. - Any dependency this would imply, with the reminder that stdlib and already-present code come first and a new module needs a stated reason. Facts and file citations only; the decisions belong to the tickets that consume this.
sulthan added the wayfinder:research label 2026-08-17 15:22:46 +07:00
sulthan self-assigned this 2026-08-17 15:23:25 +07:00
Author
Owner

Research done on branch research/htmx-series-list — note: docs/research/htmx-filterable-admin-series-list.md.

Findings: vendored htmx is 2.0.4 (only version string in the file). filter.js is a pure client-side title filter over the already-rendered list (filter.js:1-2) — it issues no requests and never touches the URL; it depends on #search + .card[data-title] + #list and re-applies on htmx:afterSwap.

All six needs are covered by the vendored 2.0.4, verified in the file itself, no new dependency:

  • Bookmarkable filter/sort: hx-get with query params + hx-push-url (hx-replace-url for replace) — the tab links already prove the pattern (app.html:55-56); docs require the pushed URL to render a full page, which the repo satisfies.
  • Debounced search: hx-trigger="keyup changed delay:500ms" (docs trigger-modifiers) — server-driven, unlike the client filter.
  • Paging: no htmx paging attribute; load-more = hx-get + hx-swap="beforeend"/revealed, numbered pages = the tab pattern with hx-push-url. Same primitives, different swap/URL semantics.
  • Per-row re-render: hx-target + hx-swap="outerHTML" + hx-swap-oob (all in-tree in card.html/chrome.html).
  • Self-refresh beside a filtered list: hx-trigger="every 30s" scoped to its own block (the Lanes pattern, lanes.html:11), or the client filter is re-applied on htmx:afterSwap (filter.js:48).
  • Confirm: hx-confirm (zero JS) or the existing inline confirm row (card.html:106-140 + filter.js:102-118) — both already in-tree.

Only caveat: filter.js is loaded on the library page only, not on /admin (admin.html:16); and client-side filter state is not URL-addressable without hand-written pushState JS. No PR opened, main untouched.

Research done on branch `research/htmx-series-list` — note: `docs/research/htmx-filterable-admin-series-list.md`. Findings: vendored htmx is 2.0.4 (only version string in the file). filter.js is a pure client-side title filter over the already-rendered list (filter.js:1-2) — it issues no requests and never touches the URL; it depends on #search + .card[data-title] + #list and re-applies on htmx:afterSwap. All six needs are covered by the vendored 2.0.4, verified in the file itself, no new dependency: - Bookmarkable filter/sort: hx-get with query params + hx-push-url (hx-replace-url for replace) — the tab links already prove the pattern (app.html:55-56); docs require the pushed URL to render a full page, which the repo satisfies. - Debounced search: hx-trigger="keyup changed delay:500ms" (docs trigger-modifiers) — server-driven, unlike the client filter. - Paging: no htmx paging attribute; load-more = hx-get + hx-swap="beforeend"/revealed, numbered pages = the tab pattern with hx-push-url. Same primitives, different swap/URL semantics. - Per-row re-render: hx-target + hx-swap="outerHTML" + hx-swap-oob (all in-tree in card.html/chrome.html). - Self-refresh beside a filtered list: hx-trigger="every 30s" scoped to its own block (the Lanes pattern, lanes.html:11), or the client filter is re-applied on htmx:afterSwap (filter.js:48). - Confirm: hx-confirm (zero JS) or the existing inline confirm row (card.html:106-140 + filter.js:102-118) — both already in-tree. Only caveat: filter.js is loaded on the library page only, not on /admin (admin.html:16); and client-side filter state is not URL-addressable without hand-written pushState JS. No PR opened, main untouched.
Author
Owner

Resolved. Findings in docs/research/htmx-filterable-admin-series-list.md, committed as 00ddbca on the throwaway branch research/htmx-series-list (not pushed, no PR, main untouched).

Answer: nothing new is needed. The vendored htmx is 2.0.4, and every primitive a filterable Series list wants is present in that build and already used somewhere in tree.

  • URL-addressable filter/sort: hx-get plus hx-push-url / hx-replace-url — a swap alone never touches the address bar, and the docs require a pushed URL to render a full page, which this repo's handlers do. The tab links already prove the pattern (templates/app.html:55-56).
  • Debounced search: hx-trigger="keyup changed delay:500ms", server-driven.
  • Paging: htmx has no paging attribute. Load-more is hx-get + hx-swap="beforeend" (or revealed); numbered pages are the tab pattern plus hx-push-url. Same primitives, different swap and URL semantics — so this is an IA decision, not a capability limit.
  • Per-row re-render without redrawing the list: hx-target + hx-swap="outerHTML", or hx-swap-oob — both already in card.html / chrome.html.
  • A self-refreshing block beside a filtered list: keep hx-trigger="every 30s" scoped to its own fragment, as lanes.html:11 does.
  • Confirm-gating: hx-confirm (zero JS) or the existing inline confirm row.

Two caveats the consuming tickets must absorb:

  1. static/filter.js is a pure client-side title filter over an already-rendered list (contract: #search + .card[data-title] + #list, re-applied on htmx:afterSwap) — it issues no requests and changes no URL. It is also not loaded on /admin (admin.html:16). So it is not reusable for the Series view as-is: client-side filter state cannot be bookmarkable without hand-written pushState, which is exactly what the IA ticket asked for. Server-side filtering with hx-push-url is the path that satisfies both.
  2. Every cited attribute was verified present in the vendored 2.0.4 bundle rather than assumed from current docs; 2.0.5–2.0.9 contain no relevant changes and remove nothing used here.

No dependency implied.

Resolved. Findings in `docs/research/htmx-filterable-admin-series-list.md`, committed as `00ddbca` on the throwaway branch `research/htmx-series-list` (not pushed, no PR, `main` untouched). Answer: **nothing new is needed.** The vendored htmx is 2.0.4, and every primitive a filterable Series list wants is present in that build and already used somewhere in tree. - URL-addressable filter/sort: `hx-get` plus `hx-push-url` / `hx-replace-url` — a swap alone never touches the address bar, and the docs require a pushed URL to render a full page, which this repo's handlers do. The tab links already prove the pattern (`templates/app.html:55-56`). - Debounced search: `hx-trigger="keyup changed delay:500ms"`, server-driven. - Paging: htmx has no paging attribute. Load-more is `hx-get` + `hx-swap="beforeend"` (or `revealed`); numbered pages are the tab pattern plus `hx-push-url`. Same primitives, different swap and URL semantics — so this is an IA decision, not a capability limit. - Per-row re-render without redrawing the list: `hx-target` + `hx-swap="outerHTML"`, or `hx-swap-oob` — both already in `card.html` / `chrome.html`. - A self-refreshing block beside a filtered list: keep `hx-trigger="every 30s"` scoped to its own fragment, as `lanes.html:11` does. - Confirm-gating: `hx-confirm` (zero JS) or the existing inline confirm row. Two caveats the consuming tickets must absorb: 1. `static/filter.js` is a **pure client-side title filter** over an already-rendered list (contract: `#search` + `.card[data-title]` + `#list`, re-applied on `htmx:afterSwap`) — it issues no requests and changes no URL. It is also **not loaded on `/admin`** (`admin.html:16`). So it is not reusable for the Series view as-is: client-side filter state cannot be bookmarkable without hand-written `pushState`, which is exactly what the IA ticket asked for. Server-side filtering with `hx-push-url` is the path that satisfies both. 2. Every cited attribute was verified present in the vendored 2.0.4 bundle rather than assumed from current docs; 2.0.5–2.0.9 contain no relevant changes and remove nothing used here. No dependency implied.
Author
Owner

Correction to the resolution comment above: the branch is pushed, not local-only. research/htmx-series-list is on origin at 00ddbca — https://gitea.violetcrown.my.id/sulthan/mangaBookmark/src/branch/research/htmx-series-list/docs/research/htmx-filterable-admin-series-list.md. It is still deliberately not merged to main and has no PR: charting should not land build artifacts, and the ticket comment carries the finding. Delete the branch once #115/#116/#118 have consumed it.

Correction to the resolution comment above: the branch is pushed, not local-only. `research/htmx-series-list` is on `origin` at `00ddbca` — <https://gitea.violetcrown.my.id/sulthan/mangaBookmark/src/branch/research/htmx-series-list/docs/research/htmx-filterable-admin-series-list.md>. It is still deliberately not merged to `main` and has no PR: charting should not land build artifacts, and the ticket comment carries the finding. Delete the branch once #115/#116/#118 have consumed it.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sulthan/mangaBookmark#123