Docs

Start with a schema, a local provider, and a DOM host. These examples describe the working foundation.

Packages

Tablin packages are private workspace packages. They are not published to npm, and no public installation command is available.

@tablin/grid exposes the DOM grid and convenience APIs. @tablin/core provides the headless controller. @tablin/themes contains the default CSS theme.

Example

This example creates a local customer grid with one editable, sortable text column. It runs inside the private workspace.

import {
  createGrid, createLocalProvider, defineColumn, defineColumns,
  field, textCodec, rowKey, columnId, datasetId,
} from '@tablin/grid';
import '@tablin/themes/tablin.css';

interface Customer { id: string; name: string }
const columns = defineColumns<Customer>()([
  defineColumn<Customer>()({
    id: columnId('name'), label: 'Customer', kind: 'text',
    field: field<Customer>()('name'), codec: textCodec,
    sortable: true, editable: true,
    width: { kind: 'flex', weight: 1 },
  }),
]);
const dataset = datasetId('customers');
const provider = createLocalProvider({
  datasetId: dataset, columns,
  rows: [{ id: 'customer-1', name: 'Ada' }],
  getRowKey: customer => rowKey(customer.id),
});
const host = document.querySelector<HTMLElement>('#customers');
if (!host) throw new Error('Customer grid host is missing.');
// The host needs a bounded height, e.g. 480px, and display:flex.
const grid = createGrid(host, {
  id: 'Customers', datasetId: dataset, columns, provider,
});
await grid.ready();

Call await grid.dispose() when the host application removes the grid. For headless use, import createController from @tablin/core.

Host

The DOM renderer needs a browser with ResizeObserver. Give the host a bounded height and a flex layout so the grid can size its scroll viewport.

<div id="customers" style="height: 480px; display: flex;"></div>

Import the theme once. Its --tl-* custom properties control surfaces, text, boundaries, selection, and focus. The implemented defaults are light, with a forced-colors mapping. A dark theme is not implemented.

Keyboard

Cell commands apply within the grid. Native editors keep their own text-entry behavior. The search shortcut belongs to the Orders playground.

Key Action
Arrow keys Move between cells.
Shift + arrow or click Select a cell rectangle within the loaded window.
Ctrl/Cmd + C or V Copy cells or paste values. A paste is one undo step.
Enter or F2 Edit the active editable cell.
Left/Right on a resize boundary Resize by 8 pixels. Hold Shift for 1 pixel.
Enter on a resize boundary Restore its column definition. Ctrl/Cmd + Enter fits a sample of mounted rows.
Enter in an editor Validate and commit the draft.
Tab in an editor Commit, then move to the next cell. Shift reverses direction.
Escape Cancel an active resize, then a draft or cell range.
Space on a cell Toggle selection for its row.
Ctrl/Cmd + Z Undo an edit. Add Shift to redo.
Enter or Space on a header Cycle that column’s sort order.
/ Focus the playground search field when outside a text field.

Double-clicking an editable cell also starts editing. In the playground, Shift-click a sortable header to build a multi-column sort.

Drag a header boundary to preview a width, then release to commit. Escape cancels. Double-click fits that column using a sample of up to 32 mounted rows. The Columns panel offers Fit visible columns and Reset widths. Fit is labelled as sampled and never scans the complete result. Hidden columns retain their width overrides.

Paste accepts quoted TSV and CSV, including multiline fields. A single value fills the selected rectangle; larger sources must fit exactly. Invalid values, read-only cells, and unloaded destinations reject the entire paste. Ranges currently cover loaded rows and visible columns.

Data

The host owns its source records and backend authority. The local provider clones plain structured records, publishes immutable row envelopes, and commits validated patches with row-version checks.

The Orders playground keeps edits in memory for the current session. Reloading the page or replacing the dataset discards those changes. Amounts use ordinary numbers; the example is not an exact-decimal accounting implementation.

See Status for the implemented boundaries and Benchmarks for measurement scope.