Streaming Element streams

Element streams

Add one complete row per async-iterable element.

Use connectElementStream when every yielded value is a complete row. The chat grid below starts empty; each element the async generator yields is appended as a new row:

Streaming chat grid

Turn a streaming LLM response into rows with connectElementStream and append them to the grid as they arrive.

.md

Signature

ts
function connectElementStream<
  TRow extends object,
  TRowId extends string | number,
>(
  rowModel: RowModelLike<TRow, TRowId>,
  stream: AsyncIterable<TRow>,
): StreamConnection;

The structural RowModelLike contract accepts atomic { add, update, remove } transactions. A Pretable local row model satisfies it directly.

React recipe

The grid above owns its rowModel with useMemo, opens the connection inside useEffect, and disposes both the connection and the row model on unmount — see its ChatGrid.tsx in the Code tab. It passes prompt through to a responseEventsToChatRows async generator, since Responses API streams yield lifecycle and text-delta events, not rows: the generator accumulates text deltas and yields a complete { id, role, content, tokens, latencyMs } value only when a response.completed event arrives (response-events-to-chat-rows.ts, same tab).

Two required props are easy to drop when hand-rolling this: PretableSurface needs both ariaLabel and viewportHeight, as the grid above passes them — neither is optional.

SSE recipe

ts
connectElementStream(rowModel, fromEventSource("/api/events"));

Raw JSON

ts
const response = await fetch("/api/events");
const strings = response.body!.pipeThrough(new TextDecoderStream());
connectElementStream(rowModel, parseElementStream<Row>(strings));

See Parsers →.