Something went wrong

Thank you for being patient! We're working hard on resolving the issue

Rows - Lona Docs Log in

Rows

Rows are the main building blocks of a sheet. Some rows hold data, some organize other rows, and some provide specialized views such as calendars, graphs, or generated reports.

Most SDK code works with rows through a SheetHandle:

for (const row of sheet.rows.list) {
  console.log(row.type, row.label);
}

What Every Row Has

Every row has a few common concepts, even when the type is different:

FieldMeaning
idThe row's RowLocalId — in-memory identity
descriptorImmutable role + dtype definition (see below)
typeThe row's wire type ("calendar", "number", …)
labelHuman-readable display name
lookupKeyOptional stable name for programmatic access
timeScaleHow the row maps onto dates and periods
attributesType-specific configuration bag

Some rows primarily store cells. Others primarily provide structure or derived views.

Finding Rows

const byId = sheet.row("r_0123456789abcdef0123456789abcdef");
const byLabel = sheet.row({ label: "Weight" });
const byLookupKey = sheet.row({ lookupKey: ":revenue" });
const byType = sheet.row({ type: "number" });

Use labels when the query is user-facing. Use lookup keys when the reference needs to survive renames.

The Row Tree

Rows live in a tree, not just a flat list. Group rows, timeline rows, and other container-style rows can own children.

const tree = sheet.tree();

for (const node of tree.nodes) {
  console.log(node.id, node.children.length);
}

This is the important public model:

  • a sheet has rows
  • rows can have children
  • the tree determines structure and display context

Roles: Source / Layout / Renderer / Alias

Every row has a role on its descriptor — the governing axis of its behavior. Four roles, four concrete base classes:

RoleBase classWhat it does
sourceSourceRowOwns or computes data (user edits, provider pushes, formulas)
layoutLayoutRowRendering container — timeline, canvas, grid, list, column
rendererRendererRowFills a single slot inside a layout (column.text, canvas.hrule, …)
aliasAliasRowFigma-style template instance with props + overrides
import { SourceRow, LayoutRow, RendererRow, AliasRow } from "@tento-lona/sheets";

const row = sheet.row({ label: "Weight" });

if (row instanceof SourceRow) {
  // Has cells(), setCell(), facades, etc.
}

Most app code never needs to check the role directly — use facades (see below) or the row's type string when branching.

Common Row Families

The exact row type list evolves over time, but most rows fit into a few broad families:

FamilyExamplesWhat they do
Basic data rowstext, number, checkmark, formulaStore or compute scalar values
Calendar and time rowscalendar, calendar-list, timezoneShow time-based data and events
Structural rowsgroup, block, timeline, calendar-monthOrganize or present child rows
Data viewsgraph, data, data-canvas, data-series, data-rendererVisualize or transform data
Specialized rowsweather, logs, ai-reportIntegrations or generated content

For most applications, the useful question is not "what is the full internal row architecture?" but "what kind of row am I working with, and what should the user be able to do with it?"

Labels, Keys, And Identity

Three row concepts are easy to mix up:

  • label is for display
  • lookupKey is a stable named reference (e.g. :revenue or :~weather)
  • RowLocalId is the in-memory identity used by trees and UI state

If you need a durable reference, prefer a lookup key or row key over a label. If you need to key a Map or work with sheet.tree(), use the RowLocalId you already have.

See Row Keys and Row Identity.

Virtual And System Rows

Not every visible row is a normal user-created row.

  • Virtual rows are generated from another row (e.g. virtual(r_...|calendar-list) under a calendar row)
  • System rows are created by the framework (system(header), system(footer))

These rows are still part of the tree and still have identifiers, but they usually behave more like structure than user-authored content.

Typed Access: Facades

For rows whose cells carry object data — calendar events, tasks, weather observations, scheduling links — use facades. A facade is obtained via row.as(FACADE_KEY) and gives you a typed API over the row's cells without hand-parsing attributes or CellEntry unions.

import {
  EVENTS_FACADE,
  TASKS_FACADE,
  WEATHER_FACADE,
  DATA_FACADE,
  SCHEDULING_LINK_FACADE,
} from "@tento-lona/sheets";
import { NaiveDate } from "@tento-chrono";

// Calendar events — partial-day + full-day queries
const calendarRow = sheet.row({ type: "calendar" });
const events = calendarRow?.as(EVENTS_FACADE);
if (events) {
  const today = NaiveDate.today();
  for (const event of events.eventsOn(today)) {
    console.log(event.summary, event.start, event.end);
  }
}

// Tasks — timed + due + slot queries
const tasksRow = sheet.row({ type: "tasks" });
const tasks = tasksRow?.as(TASKS_FACADE);
if (tasks) {
  for (const task of tasks.tasksInRange(range)) {
    console.log(task.title, task.status);
  }
}

// Weather — daily observations
const weatherRow = sheet.row({ lookupKey: ":~weather" });
const weather = weatherRow?.as(WEATHER_FACADE);
const observation = weather?.observationOn(today);

// Data-series — graph props, series, custom cells
const dataRow = sheet.row({ type: "data" });
const data = dataRow?.as(DATA_FACADE);
if (data) {
  for (const [key, series] of data.getAllSeries()) {
    console.log(key, series.points.length);
  }
}

Facades return null when the row isn't shape-compatible, so the optional- chain pattern above is safe. See Row Roles & Facades for the full list and the registration mechanism.

Type-Specific Attributes

For configuration that isn't cell data — calendar time bounds, formula style, graph scale — read the row's typed attribute bag:

const calendarRow = sheet.row({ type: "calendar" });
const attrs = calendarRow?.attributes<{
  startHr?: number;
  endHr?: number;
  calendarType?: string;
  timezone?: string;
}>();
console.log(attrs?.startHr, attrs?.endHr, attrs?.timezone);

const formulaRow = sheet.row({ type: "formula" });
const formulaAttrs = formulaRow?.attributes<{ style?: string; size?: string }>();
console.log(formulaAttrs?.style, formulaAttrs?.size);

The attributes<A>() generic tells the compiler the shape you expect; the runtime returns {} when the row has no attribute bag.

See Also