Toggle

A small composable Hono + htmx component backed by shared Yjs state. Each instance owns one boolean at toggle:<instance>.value and stays synchronized across clients through named Server-Sent Events.

Files

FilePurpose
index.tsxToggle routes, rendered button fragments, Yjs mutations, SSE synchronization, and exports.
toggle.meta.tsxMachine-readable contract plus the handler and metadata UI mounted at the component root.
README.mdUsage and endpoint reference.
template.tsxParked fragment/template experiment; it is not mounted by index.tsx.

How it works

  1. GET / renders the component metadata UI with interactive GET routes.
  2. GET /list reads existing toggle:* maps from Yjs and returns their instance names as autocomplete options; it never seeds instances.
  3. Choosing an instance on a parameterized GET route uses htmx path parameters to open that example.
  4. GET /:instance renders a persistent wrapper with one SSE connection.
  5. The wrapper loads either /:instance/on or /:instance/off based on the current Yjs value.
  6. Clicking the button posts the opposite route, which writes value and swaps only the button with outerHTML.
  7. Every real value change emits an SSE event named on or off, updating other connected buttons.

No transition logic or client-side state store is required.

Routes

The paths below are relative to the component mount point. In the combined gallery, the handler is mounted at /toggle.

RouteBehavior
GET /Render the metadata UI with route controls.
GET /listReturn a datalist populated from existing Yjs toggle instances.
GET /:instanceRender the persistent htmx/SSE wrapper.
GET /:instance/onWait until the value is true, then render the ON button. Optional ?timeout=ms; default is 30 seconds.
POST /:instance/onSet the value to true and render the ON button.
GET /:instance/offWait until the value is false, then render the OFF button. Optional ?timeout=ms; default is 30 seconds.
POST /:instance/offSet the value to false and render the OFF button.
GET /:instance/streamStream named on and off events when value changes.
GET /:instance/inspectReturn the shared Yjs document as JSON for debugging.

Composition

import { handler as toggle } from "./components/toggle"; app.route("/toggle", toggle);

Open /toggle for the component contract, or navigate directly to an instance such as /toggle/job1.

Standalone export

The default export is a fetch handler. Its root renders the same metadata UI.

import toggle from "./components/toggle"; export default toggle;

Dependencies

The parent Yjs factory provides:

  • state("toggle") middleware for the instance map and long-poll helper.
  • instancePath(c) for mount-safe URLs.
  • changes(map, signal) for Yjs change observation.
  • The shared JSX renderer, htmx, SSE extension, Iconify, and Tailwind browser runtime.