Intent-event index
Every event the shipped behaviors dispatch — name, target, when it fires, and its payload — generated from the source on each build. This is the integration API: your app listens to these and decides what to persist. For how the behaviors work (init-once, delegation, import paths), read JS behaviors once.
Intent events — the integration API generated
Behaviors never talk to your server; they dispatch an intent event and your app owns the data layer. These payloads are versioned API (see Versioning): a field changing shape or meaning is a Breaking change. This table is generated from the dispatch sites in source — it cannot drift.
| Event | Dispatched on | When | detail |
|---|---|---|---|
| bo:cell-change | the edited field (input/select/textarea; bubbles) | a cell in a data-row-edit row changes — typing, a select pick, a checkbox toggle, or a behavior-driven reformat (money/unit precision). The realtime feed for subtotal math. |
|
| bo:combobox-select | the combobox <input> (bubbles) | an option is committed — click, or Enter on the active option |
|
| bo:row-cancel | the cancelled <tr> (bubbles) | Cancel is activated; native fields are already restored — listen to restore consumer-rendered cell content the framework doesn't own (e.g. tag-input chips) |
|
| bo:row-save | the edited <tr> (bubbles) | Save is activated on a dirty row (batch mode), or any change commits in data-row-edit="live" mode; after the event, current field values become the new baseline (Cancel restores to them) |
|
| bo:scan | the [data-scan-input] field (bubbles) | the terminator key arrives (default Enter, data-scan-terminator to override); the field is cleared and refocused for the next scan |
|
| bo:table-export | the [data-table-export] button (bubbles) | the export button is clicked; the listener produces the file (server round-trip or client-side) — the framework only signals |
|
| bo:table-load-more | the [data-table-load-more] button (bubbles), or a windowed list's evicted spacer <tbody> when no such button exists | the button is clicked, or is in view (IntersectionObserver — including immediately at initLoadMore() if it is already in view); or a windowed table's evicted chunk scrolls back near the viewport |
|
| bo:tag-add | the .bo-tag-input container (bubbles) | Enter is pressed in the field with non-empty text; the field is cleared immediately |
|
| bo:tag-remove | the removed .bo-tag-input__tag (bubbles) | its remove button is clicked, or Backspace is pressed in the field while empty (removes the last tag) |
|
| bo:tree-toggle | the branch's toggle button (bubbles) | a branch expands or collapses — the hook for fetch-on-expand (lazy-load a big branch's rows, htmx or fetch) and for expand-all / expand-to-level controls built in app code |
|
All bubble, so one document-level listener works per event type — the same delegation model the inits use:
document.addEventListener("bo:row-save", (e) => {
const { row, rowId } = e.detail; // typed shape: see the table above
const values = Object.fromEntries(new FormData(row.closest("form")) );
fetch(`/pos/${rowId}`, { method: "PATCH", body: JSON.stringify(values) });
});