# Sheets docs

> Install @texuli/sheets, load a workbook, evaluate formulas, show the grid. In development. Owned formula engine.

Language: en
Canonical: https://texuli.com/guides/solutions/sheets/
Markdown: https://texuli.com/guides/solutions/sheets.md (this page). Every texuli.com page has a Markdown twin at its URL plus `.md` (the home page is https://texuli.com/index.md), and any page URL answers `Accept: text/markdown` with its twin instead of HTML.
Last Updated: 2026-11-13

---

Guides

Install @texuli/sheets, load a workbook, evaluate formulas, show the grid. In development. Owned formula engine.

[Back to overview](https://texuli.com/solutions/sheets/)

## What Sheets is

Sheets is an embeddable spreadsheet: `@texuli/sheets` holds an owned formula engine (a linear-time parser into the `@texuli/core/expression` AST, 54 documented functions, a dependency graph with incremental recalculation), a framework-free workbook model, CSV import and export, and an accessible Svelte 5 grid view. The package is published as `0.18.0` and is **in development** (pre-1.0). Pin the exact version or use `^0.17.0`.

It is not a hosted spreadsheet service. Collaboration, localized formula display and native (Kotlin) evaluation are planned, not shipped. The host app stores the workbook.

The technical docs you are reading live at `/guides/solutions/sheets/`.

## What you get

- A validated workbook as data (`format: "texuli-sheet"`, `formatVersion: 1`).
- An owned formula language: no `INDIRECT`, `OFFSET`, `LAMBDA` or `RAND`.
- Structural edits that rewrite references.
- CSV in and out that keeps formula injection neutralized.
- `SheetView` over the `@texuli/data` grid editing layer.

There is no HTML sink. Values paint as text.

## Install

Svelte 5 (`^5.57.2`) is a peer of `@texuli/sheets`. Import `@texuli/tokens/base.css` once.

```
npm install @texuli/sheets
```

## Load and show a sheet

Sheets from a file, an agent or a share link go through `loadUntrustedSheet` first.

```
<script lang="ts">
  import { loadUntrustedSheet } from '@texuli/sheets/model';
  import { SheetView } from '@texuli/sheets/view';
  import '@texuli/tokens/base.css';

  let { json }: { json: string } = $props();
  const loaded = loadUntrustedSheet(json);
  let sheet = $state(loaded.ok ? loaded.sheet : null);
</script>

{#if sheet}
  <SheetView bind:sheet now={() => Date.now()} />
{/if}
```

## Drive the workbook

```
import { createWorkbook, displayValue, loadUntrustedSheet } from '@texuli/sheets/model';

const loaded = loadUntrustedSheet(json);
if (loaded.ok) {
  const workbook = createWorkbook(loaded.sheet, { now: () => Date.now() });
  workbook.setInput('costs', 0, 1, 150);
  displayValue(workbook.value('costs', 2, 1));
  const next = workbook.toDocument();
}
```

## Workbook

The canonical document is data: `format`, `formatVersion`, optional `meta`, and `sheets`. Each tab has a stable `id`, a `name` formulas use, `rows`, `columns` and `cells` keyed by A1 address. `validateSheet` refuses unknown members, sizes past `SHEET_LIMITS`, control and bidi characters, and formulas that do not parse. It never throws.

`loadUntrustedSheet` from `@texuli/sheets/model` bounds work then validates. `createWorkbook` keeps computed values current; `setInput` recalculates only dependents.

```
import { createWorkbook, loadUntrustedSheet, validateSheet } from '@texuli/sheets/model';
```

## Owned formula engine

`parseFormula` and `evaluateFormula` live in `@texuli/sheets/formula`. The parser is linear-time into the `@texuli/core/expression` AST. Fifty-four documented functions sit in a closed table. Evaluation is bounded: overruns are `#LIMIT!`, cycles are `#CYCLE!`. `TODAY` and `NOW` read the clock the host passes.

```
import { evaluateFormula, parseFormula } from '@texuli/sheets/formula';

const parsed = parseFormula('=SUM(B2:B4)');
```

Most hosts never call these directly: `createWorkbook` parses, binds and evaluates every cell.

## CSV

`@texuli/sheets/csv` parses and writes CSV, imports as a sheet and exports a sheet. Import keeps `=…` fields as text unless the caller opts in. Export neutralizes formula injection (`=`, `+`, `-`, `@`, tab, carriage return).

## Sheet view

`SheetView` from `@texuli/sheets/view` is the accessible spreadsheet with tabs and a formula bar. It sits on the `@texuli/data` grid editing layer. Bind the document with `bind:sheet` and pass `now` so `TODAY` and `NOW` have a clock.

The cell editor loads lazily on the first Enter or F2.

## Player host

`createSheetPlayerHost` from `@texuli/sheets/host` is the sheet half of the player's `sheetHost` seam. Pass it as `sheetHost` on `Player`. Agents emit sheets as data through the catalog `spreadsheet` id; `checkSheetDraft` from `@texuli/sheets/model` is the draft check the catalog injects as `checkSheet`.

## Grid

The view is the data grid's APG grid with one tab stop, arrow-key navigation, Enter or F2 to edit, Escape to cancel, undo and redo, and TSV copy and paste. Columns are named by their letters. The first column holds row numbers. The formula bar is a named group. Formula errors are announced.

The cell editor is named by its column letter, for example `textbox` `B`. Host tests await it before typing.

## No HTML

Values paint as text. There is no `{@html}`, `innerHTML`, `eval` or `new Function`.

## Status

Sheets is **in development**. `@texuli/sheets` is on npm as `0.18.0`. Under 0.x a new minor may break. Native evaluation is planned, not built.

## Not built

- Collaboration on `@texuli/document/sync`
- Localized formula display
- Native (Kotlin) evaluation
- A hosted spreadsheet or storage service

Hard limits include 10,000-item ranges and 32,768-character strings. The formula language has no `INDIRECT`, `OFFSET`, `LAMBDA` or `RAND`.

## Untrusted sheets

A sheet from an agent, a file or a share link is untrusted data. Use `loadUntrustedSheet` from `@texuli/sheets/model` before any deep work. `validateSheet` and `checkSheetDraft` return diagnostics instead of throwing.

## Catalog and skill

Agents emit a `spreadsheet` catalog node (blueprint spec `0.8.0`). `@texuli/player` paints it through `createSheetPlayerHost`. The Texuli skill covers the package under `skills/texuli/build-ui/SKILL.md`.

Do not invent a hosted runner or an MCP operation that is not in `@texuli/tools`. Formulas stay in the closed language; they never reach the host except `TODAY` and `NOW` through the clock the host passes.
