Skip to content
Sheetwrite

Sheetwrite / Documentation

Adapter lifecycle

Initialization, readiness, resets, and transaction ownership across every Sheetwrite framework adapter.

Every adapter follows one lifecycle:

  1. mount the framework component;
  2. initialize the shared WASM runtime;
  3. create one Grid generation;
  4. publish readiness;
  5. reset only when structural ownership changes;
  6. destroy the generation on unmount.

Pick a framework in any tab group below; the selection is remembered and reused across documentation pages.

Pick the ownership model

Use Sheetwrite for a data-first, uncontrolled grid: pass columns plus initial rows and let the component own the live document.

Use SheetwriteGrid for an advanced Workbook plus eager data or a datasource. It exposes the imperative Grid after readiness and keeps structural configuration under the host's control.

The imperative core has one ownership mode: the host supplies the workbook and data, awaits runtime initialization, and destroys the returned grid.

Vanilla lifecycle
import { createGrid, initSheetwrite } from "@sheetwrite/core";
await initSheetwrite();
const grid = createGrid(host, { workbook, data });
// Later, when the host DOM lifetime ends:
grid.destroy();

Readiness is generation-scoped

onReady receives { grid, generation, reason }. generation is one-based and increments whenever the adapter replaces its Grid. reason is exactly one of:

  • "initial" — the first generation after mount and WASM initialization;
  • "input-reset" — a reset-classified document input changed identity;
  • "renderer-reset"renderer, workerUrl, or renderers changed identity.

The exposed handle (React ref, Vue expose, Svelte bind:grid) is assigned before onReady runs and cleared when that generation is destroyed. Reattach subscriptions and collaboration coordinators inside onReady; never retain a stale Grid across a reset.

Controlled values do not reset the document

theme, readOnly, config, overscan, and minColumns are live: changing them updates the current generation in place without recreating the grid or replaying defaultRows. Callbacks and host sizing (height, fill, className/class, style) are also safe to change live.

Structural changes are different. Every reset-classified input is compared by identity:

ChangeResult
workbook, data, datasource, datasourceStorageNew generation, reason: "input-reset"
protectionResolver, mutationPolicy, transactionResourceLimitsNew generation, reason: "input-reset"
renderer, workerUrl, renderersNew generation, reason: "renderer-reset"
columns, defaultRows, sheetName (simple component)New derived document, reason: "input-reset"
theme, readOnly, config, overscan, minColumnsIn-place update, no reset

Keep reset-classified inputs referentially stable (module constants, memoized values, or state) unless you intend to create a new generation.

Transactions and persistence

onGridChange receives committed transactions. transaction.patches is the exhaustive document operation list; changes is the cell-level compatibility view.

Persist committed transactions
function persist(event: ChangeEvent): void {
if (event.source === "local") operationQueue.push(...event.transaction.patches);
}

Use event.reason for audit context, not to reconstruct the transaction. For offline durability and replay, persist operations with SheetwriteStore or your own PersistenceAdapter.

Initialization failures

Framework components surface initialization errors instead of rendering a dead grid. React uses fallback and onInitializationError; Vue and Svelte support fallback content or slots plus their error callback/event.

WASM initialization is process-wide and monotonic: every adapter converges on the same runtime, and when several pass an explicit wasmSource concurrently, the first source wins. While initialization has not yet succeeded, a changed wasmSource or a remount retries it; after the runtime is ready, the source is fixed for the process.

Server rendering

Importing an adapter during SSR is safe, but the grid initializes only after a browser mount. Put it behind the host framework's client boundary:

  • React/Next.js: a client component;
  • Nuxt: <ClientOnly>;
  • SvelteKit: a browser-only branch or client-mounted component.

No framework owns the global runtime. All adapters converge on the same monotonic initializer.