Reactive values
When all you want on the wire is one derived (or state) value — not a whole partial or component — you can skip the fragment entirely. The view paints named placeholders, and the channel keeps them fresh:
<!-- Display a single reactive value anywhere in the view -->
<h1>todos (<%= reactive :remaining, 0 %> left)</h1>
...
<!-- Even across multiple places -->
<p>remaining: <%= reactive :remaining, 0 %></p>
# By adding a single transmit_value line in the channel
def build_graph
@list = TodoList.new
transmit_value(:remaining) { @list.remaining }
end
reactive(name, placeholder = "", tag_name: :span) emits <span data-hibiki-value="remaining">0</span>; transmit_value wraps the block in an effect that transmits the fresh value whenever a signal the block reads changes, and the client writes it into every placeholder carrying that name — like styling by class name, one value may appear any number of times, anywhere on the page (including outside the island, e.g. a header badge). The name joins the two halves and must be page-unique across channels. Each placeholder keeps its own tag, classes, and attributes across updates (only its text changes), so different sites can style the same value differently. In Phlex components, stamp the placeholder yourself by splatting the attributes: span(**reactive_attrs(:remaining)) { "0" }.
This is transport- and shape-agnostic: transmit_value always uses the channel’s own transmit, which every ChannelController handles — so it works the same whether the page runs the generic packaged controller or a ChannelController subclass, and it composes with a page whose other fragments ride Turbo broadcasts: one channel can serve a fragment over broadcast and a value over transmit at the same time. A subclass that overrides received should call super (or handle the value message itself) to keep reactive values live.
Cost and caveats: this is cheap — it rides the island’s existing subscription and controller (no new Stimulus instance, no new channel), adding just one server-side effect and a tiny payload per value. Values are text, never markup — the client assigns textContent, so nothing is interpreted as HTML; for markup, use a fragment. And when several values always change together, one partial/component fragment beats N spans.
The data-hibiki-* attributes the helpers emit are a private contract with the vendored JS — they version together; don’t hand-write them in app code. The helper interface’s shape is inspired by phlex-reactive’s on(...) actions.