ADR-001 Accepted 2026-05-20

Alpine.js for Catalog UI Widgets

Interactive catalog UI with no build step, no server, and no Node.js dependency.

Context

The catalog UI mockup (catalog-mockup.html) must run as a static HTML file with no server and no build step. It will be shared as a standalone file during the prototype phase and must open correctly from file:// in any modern browser.

We need: data rendering from embedded JSON, a card/list view toggle, category filter tabs, search input, and rank badge logic. All without installing anything.

Decision

Use Alpine.js v3 (loaded via CDN) for all client-side interactivity in catalog-mockup.html and related prototype pages.

Alpine provides x-data, x-for, x-if, x-on, and x-text directives directly in HTML markup. No compilation step. No module bundler. No npm install. Embedded JSON is read via JSON.parse(document.getElementById('catalog-data').textContent) to work around file:// CORS restrictions on fetch().

Consequences

Positive
  • Works from file:// — no CORS, no server required
  • No build toolchain; edit HTML and reload
  • HTML templates remain readable without JS expertise
  • ~15 KB gzipped; negligible page-weight impact
  • Declarative x-for over JSON array renders the entire catalog in one template
Negative
  • x-show conflicts with Bootstrap d-flex (!important); must use x-if (DOM removal) instead — more re-renders
  • HTMLHint alt-require rule does not understand :alt dynamic bindings; workaround: add both static alt="" and dynamic :alt="..." to every <img>
  • No SSR, no routing, no code splitting — not suitable for production at scale
  • Alpine state is not serialisable; cannot deep-link to filtered/sorted views

Alternatives Considered

OptionWhy not chosen
React / Next.js Requires Node.js build step; heavyweight for a prototype shared as a single HTML file
HTMX Most interactive features require a server to return HTML fragments; client-only state would still need Alpine
Vanilla JS No template syntax for list rendering; manually building DOM nodes for 15+ ads is verbose and fragile
Vue 3 (CDN build) Viable alternative; Alpine was chosen for its lower conceptual surface and HTML-first philosophy matching the static-doc context