Examples
Concrete, copy-pasteable examples covering the common patterns. Each is a complete, working feature — with the live reactive component rendered on its page and its source read straight off the file, so the demo and the code can never drift.
The examples#
Each page below renders its real reactive component inline — click it, it round-trips. They build from the smallest reactive component up to record-backed actions, live broadcasts, declared-once collections, and the two flagships — the inbox and the kanban board — that compose everything.
| Example | What it shows |
|---|---|
| Counter | State-backed — the smallest reactive component. Click → server → re-render, no DB row. |
| Payment split | Nested bracketed params, auto-collected siblings, and a live reactive_compute + reactive_text preview that paints before the debounced save. |
| Cross-tab chat | Record-backed action and broadcast → live cross-tab sync, zero JS. |
| Live todo list | Per-row record-backed components: add / toggle / rename / archive, optimistic toggle + delete, Enter-to-add, morph-in-place, broadcast on change. |
| Inline edit + dirty tracking | Show ↔ edit (Enter saves, Escape cancels) plus an “Unsaved” badge + leave-guard with zero shipped state. |
| Notifications / badges | Pure broadcast — a background event pushes a live re-render, plus a broadcast_to(js:) cross-tab pulse. |
| Reactive collections | Add / remove rows + a running count + an empty state, declared once with reactive_collection, optimistic dismiss + a self-dismissing flash. |
| File uploads & custom types | :file / [:file] params (multipart FormData), a nested-hash param alongside the file (#39), and a custom Phlex::Reactive.param_type. Code-first — no live demo. |
| Loading states | busy: + busy_on + the always-on aria-busy, with a latency toggle to make the pending window visible. |
| Client-only ops | on_client tabs / outside-close menu / accessible drawer — zero fetches, zero custom JS. |
| Failure surface | error_flash + data-reactive-error + dismiss_after: — what an adopter gets for free when an action fails. |
| Team inbox (flagship) | The whole toolkit in one UI: collection rows, optimistic archive that reverts on failure, cross-tab broadcast, an on_client kebab, and error flashes. |
| Project board (flagship) | The kanban: cards move across lanes with enter/exit effects (per-visitor style picker incl. random), live count badges in every tab via broadcast_to(js:), nested reactive rows with inline rename, confirm-gated archive. |
Every headline feature now has a live page. Pick a capability:
| Feature | Where it's shown (live) |
|---|---|
Client-only ops — on_client + js (show/hide/toggle, set_attr/toggle_attr, focus, text, dispatch, submit, paste_into, transitions): zero round trips | Client-only ops, Todo list, Team inbox |
Client-side computes — reactive_compute + reactive_text (a live preview / char counter that paints with no round trip) | Payment split |
Declarative loading states — busy: / busy_on (+ the always-on aria-busy / data-reactive-busy) | Loading states, Todo list, Collections, Team inbox |
Dirty-field tracking — reactive_dirty / warn_unsaved: / only: (enable Save only on change; warn before leaving) | Inline edit |
Optimistic visual hints — optimistic: (flip a checkbox / hide a row instantly; revert on failure) | Todo list, Collections, Team inbox |
Keyboard triggers — event: "keydown.enter" / "keydown.esc" (Enter-to-add, Escape-to-cancel) | Todo list, Inline edit |
Debounced / morph editing — debounce: live-as-you-type + reply.morph to keep the caret | Payment split, Inline edit |
Effects — reactive_effects enter/exit/update + per-call effect: (incl. random) — see the Effects guide | Project board |
Live broadcasts — broadcast_to(replace:) / broadcast_to(append:) / broadcast_to(js:) → cross-tab sync | Chat, Notifications, Todo list, Team inbox, Project board |
Failure surface — error_flash / data-reactive-error / dismiss_after: / timeout + offline | Failure surface, Team inbox |
Combobox keyboard navigation — reactive_listnav (Arrow keys move a client highlight, Enter picks), composed via mix | Searchable combobox demo |
File uploads & custom param types — :file / [:file] (multipart FormData), Phlex::Reactive.param_type | File uploads & custom types (code-first) |
File uploads (:file / [:file] params, multipart FormData) and custom param types (Phlex::Reactive.param_type) have a dedicated code-first walkthrough — no live demo, because a public upload endpoint is a storage/abuse surface. The payment split is the closest live cousin: the nested-params / auto-collected sibling-fields example that a FormData upload extends.