@jsvision/datagrid / EditableDataGrid
Class: EditableDataGrid<T>
Documented in: Data Grid
Defined in: datagrid/src/grid.ts:400
An editable, self-drawing data grid over a typed column model and a GridDataSource. It is a Group, so a plain instance is not itself a focus target — focus its EditableDataGrid.rows body renderer to move the cursor and edit.
Example
import { at, Group, createEventLoop, resolveCapabilities, signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string; }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }, { id: 2, name: 'Bo' }]);
const columns = [
column({
id: 'name', title: 'Name',
value: (r: Row) => r.name,
parse: (t) => t, // editable: parse + set present
set: (r, v) => { r.name = v; },
}),
];
const grid = at(
new EditableDataGrid<Row>({
columns,
source: fromRows(rows, { rowKey: (r) => r.id }),
onCommit: (c) => String(c.value).trim().length > 0, // veto an empty name
}),
0,
0,
20,
6,
);
const root = new Group();
root.add(grid);
const caps = resolveCapabilities().profile;
const loop = createEventLoop({ width: 20, height: 6 }, { caps });
loop.mount(root);
loop.focusView(grid.rows); // focus the body: arrow keys move, F2/Enter/type edits, Enter commitsExtends
Group
Type Parameters
T
T
Constructors
Constructor
new EditableDataGrid<
T>(opts):EditableDataGrid<T>
Defined in: datagrid/src/grid.ts:525
Parameters
opts
The columns, the source, optional zebra striping, and an optional onCommit veto sink.
Returns
EditableDataGrid<T>
Overrides
Group.constructor
Properties
background?
optionalbackground?: keyof Theme
Defined in: ui/dist/view/group.d.ts:55
Optional background theme role filled before children compose, so overlap never leaks cells.
Inherited from
Group.background
bounds
bounds:
Rect
Defined in: ui/dist/view/view.d.ts:61
Parent-relative integer rect; written by the layout pass — read it in draw/hit-testing.
Inherited from
Group.bounds
castsShadow
castsShadow:
boolean
Defined in: ui/dist/view/view.d.ts:91
When true, the renderer paints a drop shadow on the cells just below and to the right of this view, in paint order (a later sibling's shadow falls over an earlier one). Default false. The Desktop sets it per window.
Inherited from
Group.castsShadow
centered
centered:
boolean
Defined in: ui/dist/view/view.d.ts:98
When true, the layout pass recentres this view within its parent after layout — origin = (parent - self) / 2 on both axes. Intended for absolutely-placed views (a modal dialog, a message box) whose size is fixed and whose origin would otherwise be placed by the caller. Default false; Dialog sets it when centered.
Inherited from
Group.centered
children
readonlychildren:View[]
Defined in: ui/dist/view/group.d.ts:53
Ordered children; array order is paint order (back-to-front).
Inherited from
Group.children
focusable
focusable:
boolean
Defined in: ui/dist/view/view.d.ts:104
Whether this view can receive keyboard focus. Effective focusability also requires the view to be visible and enabled with no hidden/disabled ancestor. Default false; the focus manager drives the state.focused flag.
Inherited from
Group.focusable
grabsFocus
grabsFocus:
boolean
Defined in: ui/dist/view/view.d.ts:113
Whether a mouse-down that hits this view moves keyboard focus to it. Default true — the usual click-to-focus. Set false for a control that should act on a click without stealing focus from whatever is focused (e.g. a dialog Cancel button, or a toolbar/stepper button): the click still dispatches, but the previously-focused view keeps focus, so it never fires a focus-leave side effect such as a field's blur-validation. Independent of focusable — a grabsFocus: false view can still be reached by Tab and activated by Space.
Inherited from
Group.grabsFocus
i18n
readonlyi18n:I18n
Defined in: datagrid/src/grid.ts:499
Translation service used by package-owned grid surfaces.
layout
readonlylayout:Readonly<LayoutProps>
Defined in: ui/dist/view/view.d.ts:83
Layout props for this view (direction, size, padding, absolute placement, …) — read-only.
Change them with setLayout, which is the only writer. The field and every prop on it are closed, so neither view.layout = {…} nor view.layout.rect = {…} compiles, and neither does editing a solved rect a field at a time (view.layout.rect.x = 5). That is deliberate: a wholesale assignment silently drops every prop it omits and never reflows, and an in-place prop write reflows only if you remember to ask.
Read it freely — this is where a view's solved intent lives, and layout.rect is how an absolutely-placed view reports where it was put.
Inherited from
Group.layout
overlay
readonlyoverlay:Group
Defined in: datagrid/src/grid.ts:430
The absolute overlay host on top of the grid — the cell editor mounts into it while editing.
popupOverlay
readonlypopupOverlay:Group
Defined in: datagrid/src/grid.ts:436
A second absolute overlay, above overlay, that hosts a filter popup opened from the header funnel. Kept separate from the editor overlay so a filter popup and an open cell editor never collide, and hit-transparent while empty (see EditorOverlay).
postProcess
postProcess:
boolean
Defined in: ui/dist/view/view.d.ts:117
Take part in the post-process sweep (after the focused view sees the event).
Inherited from
Group.postProcess
preProcess
preProcess:
boolean
Defined in: ui/dist/view/view.d.ts:115
Take part in the pre-process sweep (root→down, before the focused view sees the event).
Inherited from
Group.preProcess
state
readonlystate:ViewState
Defined in: ui/dist/view/view.d.ts:70
Draw-against flags. The object reference is fixed; individual fields mutate (e.g. focused).
Writing visible or disabled changes only what the next paint would draw — it does not ask for that paint. Follow such a write with invalidate (or invalidateLayout, which a visibility flip needs, since layout omits hidden views). A development build warns when a write goes unaccounted for.
Inherited from
Group.state
Accessors
rows
Get Signature
get rows():
EditableGridRows<T>
Defined in: datagrid/src/grid.ts:406
The focusable body renderer — focus this (a plain Group is not a focus target). In a frozen grid this is the center (horizontally-scrolling) panel; every panel shares one row cursor, so focusing it and moving the cursor drives all panels together.
Returns
Methods
accelerators()
accelerators(): readonly
string[]
Defined in: ui/dist/view/view.d.ts:131
The Alt+hotkey accelerator characters (lowercase) this view claims in its focus scope, for duplicate-accelerator detection. The base returns none; accelerator-bearing widgets (Button/Label/CheckGroup/RadioGroup) override it to report their ~X~ hotkey(s).
Returns
readonly string[]
The claimed accelerator chars, or an empty list when the view claims none.
Inherited from
Group.accelerators
activeMessage()
activeMessage():
string|null
Defined in: datagrid/src/grid.ts:979
The active validation/veto message shown in the grid's message band, or null when there is none. Reactive — it follows the most recent blocked commit or row-gate message and clears once the offending cell/row is valid again.
Returns
string | null
The active message string, or null.
add()
add(
child):void
Defined in: ui/dist/view/group.d.ts:72
Add a child, appending it on top (later in the array draws in front). If this group is already mounted, the child mounts immediately — its scope nested under this group's — and a reflow is scheduled for the new layout; otherwise the child mounts when this group itself mounts.
Parameters
child
View
The view to append.
Returns
void
Inherited from
Group.add
addDynamic()
addDynamic(
build):void
Defined in: ui/dist/view/group.d.ts:104
Add children reactively from a Show/For accessor, so the set of children updates itself as signals change. When the group is mounted, an effect reads the accessor, mounts any newly produced views, unmounts any that disappeared (firing their onCleanup), and schedules a reflow on change. Pass a factory that builds the combinator inside itself, not an already-built accessor — this lets the group own and dispose the combinator's reactive nodes on unmount.
Parameters
build
DynamicBuilder
A factory that constructs the combinator, e.g. () => Show(cond, then) or () => For(each, key, render).
Returns
void
Example
import { Group, View, signal, Show, type DrawContext } from '@jsvision/ui';
class Panel extends View {
draw(ctx: DrawContext) {
ctx.fill(' ', ctx.color('window'));
}
}
const open = signal(false);
const group = new Group();
group.addDynamic(() => Show(() => open(), () => new Panel())); // Panel appears when `open` is trueInherited from
Group.addDynamic
addSort()
addSort(
columnId,dir?):void
Defined in: datagrid/src/grid.ts:1012
Add or update a secondary sort key (a Ctrl+click / the multi-key API). With an explicit dir, sets-or-appends that key. Without dir: a new column is appended ascending; an existing key cycles its direction in place (asc → desc → removed), keeping its priority. An unknown columnId is ignored.
Parameters
columnId
string
The column to add or update.
dir?
Optional explicit direction; omit to append-ascending / cycle.
Returns
void
applyVariant()
applyVariant(
variant):void
Defined in: datagrid/src/grid.ts:1457
Restore a layout GridVariant saved with saveVariant. Reproduces, in a fixed sequence, the column order, visibility, width overrides, freeze, sort, and filter. An id the grid no longer has is skipped (never thrown); a column the grid has that the variant does not name keeps its current state and is appended after the named columns. A filter on a column the variant hides is retained and reappears when the column is shown.
Parameters
variant
The variant to apply.
Returns
void
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
const mine = grid.saveVariant('mine'); // persist this somewhere…
grid.applyVariant(mine); // reproduces order / width / visibility / freeze / sort / filterautoFitAll()
autoFitAll():
void
Defined in: datagrid/src/grid.ts:1507
Auto-fit every visible column (see EditableDataGrid.autoFitColumn).
Returns
void
autoFitColumn()
autoFitColumn(
id):void
Defined in: datagrid/src/grid.ts:1493
Size a column to its widest visible cell (its title or any displayed value), floored to the column's minWidth and bounded by its maxWidth (or a generous default). Stores the result as an explicit width override. An unknown id is ignored.
Parameters
id
string
The column id.
Returns
void
bind()
bind<
T>(reader,apply?,opts?):void
Defined in: ui/dist/view/view.d.ts:277
Bind a reactive value to a redraw. Creates an effect (owned by this view's scope) that reads reader() — subscribing to whatever signals it touches — runs the optional apply(value), then requests a frame: a repaint by default, or a reflow when { relayout: true }. It re-runs automatically whenever those signals change, and is disposed when the view unmounts.
Call it from onMount, not the constructor — the view's scope only exists once mounted, so a pre-mount bind throws rather than silently dropping the binding.
Type Parameters
T
T
Parameters
reader
() => T
Reads the reactive source; the signals it reads become dependencies.
apply?
(v) => void
Optional: apply the read value to the widget (e.g. store it in a field).
opts?
Pass { relayout: true } when the change affects layout, so it reflows instead of just repainting.
relayout?
boolean
Returns
void
Example
import { View, signal, type DrawContext } from '@jsvision/ui';
const count = signal(0);
class StatusLine extends View {
draw(ctx: DrawContext): void {
ctx.text(0, 0, `${count()} pending`, ctx.color('statusBar'));
}
}
const status = new StatusLine();
// In onMount, not the constructor: bind() needs the view's scope, which only exists once mounted.
status.onMount(() => {
status.bind(() => count()); // repaint the status line whenever `count` changes
});Inherited from
Group.bind
clearColumnWidth()
clearColumnWidth(
id):void
Defined in: datagrid/src/grid.ts:1338
Remove a column's explicit width override, returning it to its auto/declared width. An unknown id is ignored (no throw). The reactive counterpart of setColumnWidth without the clamp/set.
Parameters
id
string
The column id.
Returns
void
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; amount: number }
const rows = signal<Row[]>([{ id: 1, amount: 42 }]);
const columns = [column({ id: 'amount', title: 'Amount', value: (r: Row) => r.amount })];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
grid.setColumnWidth('amount', 20);
grid.clearColumnWidth('amount'); // amount returns to its auto/declared widthclearFilter()
clearFilter(
columnId?):void
Defined in: datagrid/src/grid.ts:1060
Clear one column's filter, or — with no argument — every filter.
Parameters
columnId?
string
The column whose filter to clear; omit to clear all filters.
Returns
void
clearSelection()
clearSelection():
void
Defined in: datagrid/src/grid.ts:1953
Clear the row selection and its range anchor.
Returns
void
clearSort()
clearSort():
void
Defined in: datagrid/src/grid.ts:1028
Clear all sort keys — the client path restores source order; a push-down source gets setSort([]).
Returns
void
columnOrder()
columnOrder():
string[]
Defined in: datagrid/src/grid.ts:1189
The visible column order (the full order minus hidden columns). Reactive — reading it inside an effect re-runs when the order, visibility, or a reorder changes.
Returns
string[]
The visible column ids, in order.
columns()
columns(): readonly
GridColumnInfo[]
Defined in: datagrid/src/grid.ts:1216
The full column list — every column (hidden included), in full column order — as resolved GridColumnInfo metadata (id, title, visibility, resolved freeze side, resolved width). Reactive: reading it inside an effect re-runs on any order / visibility / freeze / width change. frozen reports the resolved partition, so an over-pinned column reads 'none' (matching frozen). Independently useful for an app-built column UI.
Returns
readonly GridColumnInfo[]
One info per column, in full column order.
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
for (const c of grid.columns()) {
// { id, title, visible, frozen: 'left' | 'right' | 'none', width }
}columnWidth()
columnWidth(
id):number
Defined in: datagrid/src/grid.ts:1300
The resolved width of a column in cells: an explicit override if set, else the column's declared fixed width, else its measured auto width, else its title width. Reactive.
Parameters
id
string
The column id.
Returns
number
The resolved width in cells (0 for an unknown id).
defaultColumnLayout()
defaultColumnLayout(): readonly
GridColumnInfo[]
Defined in: datagrid/src/grid.ts:1246
The construction-time column baseline — every column visible, in construction (declaration) order, with no freeze and no width overrides. The layout a personalization Reset restores to. Its width is the resolved declared/auto width for display only; a Reset restores no override (it never copies the number back).
Returns
readonly GridColumnInfo[]
One baseline GridColumnInfo per column, in construction order.
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
const base = grid.defaultColumnLayout(); // all visible, construction order, no freeze/overridesdeleteRows()
deleteRows(
keys):void
Defined in: datagrid/src/grid.ts:2004
Remove rows by key through the data-source mutation seam, then prune those keys from the selection (a deleted row never stays selected). A no-op on the source when it is read-only (exposes no remove); the selection is still pruned either way. Keys not present are ignored.
Parameters
keys
readonly Key[]
The row keys to remove.
Returns
void
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 10, name: 'Ada' }, { id: 11, name: 'Bo' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
grid.deleteRows([10, 11]); // removed from the source and de-selectedderived()
protectedderived<T>(fn): () =>T
Defined in: ui/dist/view/view.d.ts:299
Create a stable derived accessor owned by this view's scope. The returned () => T keeps the same identity for the life of the view, so it is safe to build in the constructor and hand to child views before this view mounts. The backing computed is created lazily under the view's own scope, so it is always owned and disposed at unmount — unlike a bare computed() in the constructor, which would run before any scope exists, leak, and warn.
Reads behave sensibly across the lifecycle:
- Before mount: evaluates
fn()directly (correct current value, nothing persisted). Good for a pre-mount natural-size measure. - After mount: builds and memoizes a
computed(fn)under the view's scope. - After an unmount→remount: the memo is keyed to the scope it was built under, so a remounted view (which gets a fresh scope) re-derives under the new scope instead of returning the previous mount's disposed, now-frozen computed — keeping a
Show/For-remounted widget reactive.
Type Parameters
T
T
Parameters
fn
() => T
The derivation (pure; the signals it reads become the computed's dependencies).
Returns
A stable accessor; call it to read the derived value.
() => T
Inherited from
Group.derived
desiredCaret()
desiredCaret():
Point|null
Defined in: ui/dist/view/view.d.ts:211
Where this view wants the hardware text cursor, in view-local cells, or null for no cursor (the default — most views never show one). A focused text input overrides this to place the caret at the edit position; the event loop reads it after each frame, converts it to an absolute cell, and moves the terminal cursor there.
Returns
Point | null
The view-local caret point (0-based, relative to this view's origin), or null.
Inherited from
Group.desiredCaret
displayedRows()
displayedRows(): readonly
T[]
Defined in: datagrid/src/grid.ts:1115
The filtered + sorted rows currently displayed (reactive). This is the loaded/in-memory set the footer aggregates fold over; reading it inside an effect re-runs when a row is edited, inserted, deleted, sorted, or filtered.
Windowed sources: for a windowed source (one exposing ensureRange) this returns a length-correct lazy view, not a materialized array. Only .length and integer indexing are supported — every whole-array operation (.map/.find/.filter/spread/for..of) throws. Read .length for the count and [i] for a row (undefined at an unloaded index); do not assume a dense T[]. An eager source returns an ordinary dense array.
Returns
readonly T[]
The displayed rows, in display order — a dense array (eager) or a lazy view (windowed).
draw()
draw(
ctx):void
Defined in: ui/dist/view/group.d.ts:64
Fill the background role (if set) across the group rect; children are composed by the render root.
Parameters
ctx
DrawContext
Returns
void
Inherited from
Group.draw
duplicateRow()
duplicateRow(
key):void
Defined in: datagrid/src/grid.ts:2039
Insert a structured clone of the row identified by key, adjacent to it, carrying a fresh key from the assignKey option. A no-op (with a dev warning) when assignKey is not configured — it never inserts a key-colliding row. Also a no-op when key is absent from the display, or when the row is not structured-cloneable (holds a function, a class instance, etc.) — the clone is attempted inside a guard, so a non-cloneable row warns instead of throwing and never leaves a partial insert.
Parameters
key
The key of the row to duplicate.
Returns
void
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 10, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
// duplicateRow only inserts when assignKey is configured to mint the fresh key:
let nextId = 1000;
const grid = new EditableDataGrid<Row>({
columns,
source: fromRows(rows, { rowKey: (r) => r.id }),
assignKey: (clone) => ({ ...clone, id: nextId++ }),
});
grid.duplicateRow(10); // a clone with a fresh id is inserted right after row 10exportView()
exportView(
format):string
Defined in: datagrid/src/grid.ts:1153
Serialize the current view — the visible columns in display order, their formatted values, and the filtered + sorted rows — to CSV, HTML, JSON, or TSV. CSV/TSV are RFC-4180 (records CRLF-joined; a field with the delimiter, a ", or a newline is double-quoted, embedded quotes doubled) with spreadsheet formula-injection escaping (a cell that begins with = + - @ — the accepted tradeoff: a negative like -5 becomes '-5); HTML is a standalone document with a markup-escaped <table>; JSON is an array of objects holding the raw values keyed by column id. Hidden and synthetic (checkbox / row-number) columns are excluded; the grid never chooses a destination — it returns a string the caller writes to a file or clipboard.
Eager sources only. This serializes the resident displayed rows. On a windowed source (one exposing ensureRange) the displayed rows are a lazy window, not a full array, so this throws — a full-view export over a windowed source is a separate mechanism.
Parameters
format
The target format ('csv' | 'html' | 'json' | 'tsv').
Returns
string
The serialized document as a string.
Throws
If the grid is over a windowed source.
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string; total: number }
const rows = signal<Row[]>([{ id: 1, name: 'Ann', total: 10 }]);
const columns = [
column({ id: 'name', title: 'Name', value: (r: Row) => r.name }),
column({ id: 'total', title: 'Total', value: (r: Row) => r.total }),
];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
const csv = grid.exportView('csv'); // 'Name,Total\r\nAnn,10\r\n…' — RFC-4180, formula-escaped
const json = grid.exportView('json'); // [{ name: 'Ann', total: 10 }, …] — raw values, keyed by idfilteredCount()
filteredCount():
number
Defined in: datagrid/src/grid.ts:1087
The number of rows passing all active filters. Reactive. On the client path this is the filtered row count; on an eager push-down source source.length() already reflects the filtered set, so it equals totalCount() there (a documented v1 limitation until the windowing seam exposes a separate pre-filter total).
Returns
number
The count of rows currently shown — render "N of M" from this and totalCount.
filterModel()
filterModel():
FilterModel
Defined in: datagrid/src/grid.ts:1075
The current filter model. Reactive — reading it inside an effect re-runs when the filters change.
Returns
The active per-column filters (empty when nothing is filtered).
focusedKey()
focusedKey():
Key|undefined
Defined in: datagrid/src/grid.ts:1812
The rowKey of the focused record (reactive), or undefined when the grid is empty. Shares the same clamped cursor as focusedRow.
Returns
Key | undefined
The focused row's key, or undefined on an empty grid.
focusedRow()
focusedRow():
T|undefined
Defined in: datagrid/src/grid.ts:1799
The record under the row cursor (reactive), or undefined when the grid is empty. Re-anchored by rowKey after a sort/filter, so it follows the same record even as its display index moves — the natural binding target for a master-detail link. The cursor is clamped into range, so a transiently- stale cursor never returns undefined while rows exist.
Returns
T | undefined
The focused record, or undefined on an empty grid.
focusSignal()
focusSignal():
Signal<void>
Defined in: ui/dist/view/view.d.ts:168
Subscribe to this view's focus changes. Reading the returned signal inside a bind/effect re-runs that effect whenever this view gains or loses focus — including from another view (e.g. a Label repainting when the control it labels is focused). The signal notifies on every poke even without a value change. Lazy: the backing signal is created on first call.
Returns
Signal<void>
A signal that ticks whenever this view gains or loses focus.
Example
import { View, Button, type DrawContext } from '@jsvision/ui';
// A caption that highlights while the control it labels holds focus.
class Caption extends View {
constructor(
private readonly text: string,
private readonly target: View,
) {
super();
// Reading the target's focus signal inside bind() ties this view's repaint to the target's
// focus flips — a view can observe focus it does not own.
this.onMount(() => this.bind(() => this.target.focusSignal()()));
}
draw(ctx: DrawContext): void {
ctx.text(0, 0, this.text, ctx.color(this.target.state.focused ? 'labelSelected' : 'label'));
}
}
const ok = new Button('~O~K');
const caption = new Caption('Confirm:', ok);Inherited from
Group.focusSignal
frozen()
frozen():
object
Defined in: datagrid/src/grid.ts:1366
The resolved frozen partition: which visible columns are pinned left and right (over-pinned columns are pushed back to the center, so this reflects what actually renders frozen). Reactive.
Returns
object
The left- and right-pinned column ids, in order.
left
left:
string[]
right
right:
string[]
insertRow()
insertRow(
row,at?):void
Defined in: datagrid/src/grid.ts:1980
Insert a row through the data-source mutation seam. at is a source-array index (append when omitted). A no-op when the source is read-only (exposes no insert) — the grid never persists on its own. The row must already carry its rowKey (the caller owns key generation). With an active client sort the row re-sorts to its value-determined display position on the next derive; a push-down source owns its own ordering.
Parameters
row
T
The row to insert (already carrying its rowKey).
at?
number
The source index to splice at; appended when omitted.
Returns
void
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
grid.insertRow({ id: 10, name: 'New' }); // appended
grid.insertRow({ id: 11, name: 'Top' }, 0); // spliced at the front of the sourceinvalidate()
invalidate():
void
Defined in: ui/dist/view/view.d.ts:213
Request a repaint of this view. A no-op before the view is mounted (the first frame paints everything).
Returns
void
Inherited from
Group.invalidate
invalidateLayout()
invalidateLayout():
void
Defined in: ui/dist/view/view.d.ts:215
Request a reflow (re-run layout, then repaint). Use this when a change affects size/position, not just pixels.
Returns
void
Inherited from
Group.invalidateLayout
isBodyFocused()
isBodyFocused():
boolean
Defined in: datagrid/src/grid.ts:1817
Whether the grid body currently holds keyboard focus (used by the Tab-navigation helper).
Returns
boolean
isDirty()
isDirty(
rowKey,columnId):boolean
Defined in: datagrid/src/grid.ts:934
Whether a specific cell has an unresolved (pending) commit. Reactive — reading it inside an effect re-runs when the cell's pending state changes.
Parameters
rowKey
string | number
The edited row's stable key.
columnId
string
The edited column id.
Returns
boolean
true while the cell's commit is in flight, false once it resolves.
isEditing()
isEditing():
boolean
Defined in: datagrid/src/grid.ts:1826
Whether an in-cell editor is currently open on this grid. Note that while editing the keyboard focus is on the editor overlay, not the body — so the Tab-navigation helper treats a grid as its active target when its body is focused OR it is editing (a Tab then commits and advances by cell).
Returns
boolean
isGridDirty()
isGridDirty():
boolean
Defined in: datagrid/src/grid.ts:955
Whether any cell anywhere in the grid has a pending commit. Reactive (see EditableDataGrid.isDirty).
Returns
boolean
true if at least one cell is pending.
isInvalid()
isInvalid(
rowKey,columnId):boolean
Defined in: datagrid/src/grid.ts:968
Whether a specific cell is marked invalid — its last edit was blocked (a failed validate, an unparseable value, or a vetoed change) and never took. Reactive (see EditableDataGrid.isDirty). Clears on a successful re-commit or an abandoned edit.
Parameters
rowKey
string | number
The cell's row key.
columnId
string
The cell's column id.
Returns
boolean
true while the cell is marked invalid.
isRowDirty()
isRowDirty(
rowKey):boolean
Defined in: datagrid/src/grid.ts:944
Whether any cell in a row has a pending commit. Reactive (see EditableDataGrid.isDirty).
Parameters
rowKey
string | number
The row's stable key.
Returns
boolean
true if at least one cell in the row is pending.
measure()?
optionalmeasure(available):Size2D
Defined in: ui/dist/view/view.d.ts:85
Optional intrinsic-size hook for auto sizing — return the size this view wants for available.
Parameters
available
Size2D
Returns
Size2D
Inherited from
Group.measure
nextCell()
nextCell():
Promise<"moved"|"exit">
Defined in: datagrid/src/grid.ts:1856
Advance the cell cursor one step forward (left-to-right, top-to-bottom), wrapping at a row end. If an editor is open it is committed first; a vetoed commit keeps the editor open and returns 'moved' WITHOUT advancing — 'moved' means "the grid handled Tab; do not hand focus away", not "the cursor advanced". At the last cell of the last row it returns 'exit' (the caller moves to the next widget).
Returns
Promise<"moved" | "exit">
'moved' when the grid handled the step (advanced, or held an open editor), else 'exit'.
Example
import { at, Group, createEventLoop, resolveCapabilities, signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = at(new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) }), 0, 0, 20, 6);
const root = new Group();
root.add(grid);
const loop = createEventLoop({ width: 20, height: 6 }, { caps: resolveCapabilities().profile });
loop.mount(root);
const r = await grid.nextCell();
if (r === 'exit') loop.focusNext(); // at the grid edge → leave to the next widgetonCleanup()
onCleanup(
fn):void
Defined in: ui/dist/view/view.d.ts:315
Register a teardown callback that runs once when this view unmounts. Requires a mounted view — so call it from within onMount. Use it to release anything the view acquired (a timer, an external subscription).
Parameters
fn
() => void
The teardown callback.
Returns
void
Inherited from
Group.onCleanup
onEvent()
onEvent(
_ev):void
Defined in: ui/dist/view/view.d.ts:195
Handle an input event — a no-op by default. The event loop wraps each event in a DispatchEvent envelope and routes it to the views; override this to react to keys/mouse and set ev.handled = true to consume the event so it does not propagate further.
Parameters
_ev
DispatchEvent
The dispatch envelope (the wrapped event plus the mutable handled flag).
Returns
void
Inherited from
Group.onEvent
onMount()
onMount(
fn):void
Defined in: ui/dist/view/view.d.ts:307
Register a callback to run once when the view becomes live (after its first layout gives it bounds). This is where to call bind, since the view's reactive scope exists by then. Registering after the view is already live runs the callback immediately.
Parameters
fn
() => void
Post-mount setup.
Returns
void
Inherited from
Group.onMount
prevCell()
prevCell():
Promise<"moved"|"exit">
Defined in: datagrid/src/grid.ts:1885
Retreat the cell cursor one step (the mirror of nextCell), wrapping at column 0. An open edit is committed first; a vetoed commit keeps the editor open and returns 'moved' without moving. At (0, 0) it returns 'exit'.
Returns
Promise<"moved" | "exit">
'moved' when the grid handled the step, else 'exit' at the grid start.
Example
import { at, Group, createEventLoop, resolveCapabilities, signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = at(new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) }), 0, 0, 20, 6);
const root = new Group();
root.add(grid);
const loop = createEventLoop({ width: 20, height: 6 }, { caps: resolveCapabilities().profile });
loop.mount(root);
const r = await grid.prevCell();
if (r === 'exit') loop.focusPrev();remove()
remove(
child):void
Defined in: ui/dist/view/group.d.ts:80
Remove a child: dispose its scope (recursively disposing its descendants and running their onCleanup), detach it, and schedule a reflow. Removing a non-child (or removing twice) is a safe no-op.
Parameters
child
View
The view to remove.
Returns
void
Inherited from
Group.remove
saveVariant()
saveVariant(
name):GridVariant
Defined in: datagrid/src/grid.ts:1423
Capture the grid's full column layout — the column order, per-column width overrides and visibility, the frozen partition, the sort model, and the filter model — as a serializable GridVariant the caller persists. The grid stores nothing itself; pair it with applyVariant to restore.
Parameters
name
string
A caller-facing label for the variant.
Returns
The serializable layout snapshot (plain JSON — no functions).
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
const mine = grid.saveVariant('mine'); // { name, columns, freeze, sort, filter } — persist itselectAllDisplayed()
selectAllDisplayed():
void
Defined in: datagrid/src/grid.ts:1948
Select every displayed (filtered/sorted) row — the header checkbox's select-all target.
Returns
void
selectByClick()?
optionalselectByClick():void
Defined in: ui/dist/view/view.d.ts:202
Optional "select + raise on click" hook. Left undefined on the base, so a plain view is not a select/raise target. A container that owns z-order (a Window) overrides it to select and raise itself. The hit-test invokes the first ancestor that defines this — before delivering the mouse-down — so a click always raises the window even if the interior also consumes the click.
Returns
void
Inherited from
Group.selectByClick
selectedKeys()
selectedKeys():
ReadonlySet<Key>
Defined in: datagrid/src/grid.ts:1787
The current row selection, keyed by rowKey. Reactive — reading it inside an effect re-runs when the selection changes. The set survives re-sort/re-filter (the keys are stable); a delete prunes it.
Returns
ReadonlySet<Key>
The selected row keys (empty when nothing is selected).
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }, { id: 3, name: 'Bo' }]);
const columns = [column({ id: 'name', title: 'Name', value: (r: Row) => r.name })];
const source = fromRows(rows, { rowKey: (r) => r.id });
const grid = new EditableDataGrid<Row>({ columns, source }); // default 'multi'
grid.selectRow(1); // select the row whose rowKey is 1
grid.toggleRow(3); // add row 3 → { 1, 3 }
[...grid.selectedKeys()]; // [1, 3]
grid.clearSelection(); // {}selectRange()
selectRange(
toKey):void
Defined in: datagrid/src/grid.ts:1943
Extend the selection to toKey as a contiguous display-order range from the current anchor (or, when no anchor is set, from the focused row). A no-op on an empty grid.
Parameters
toKey
The far end of the range, in the current display order.
Returns
void
selectRow()
selectRow(
key):void
Defined in: datagrid/src/grid.ts:1923
Select exactly key, replacing any prior selection, and make it the range anchor.
Parameters
key
The row key to select.
Returns
void
setColumnOrder()
setColumnOrder(
ids):void
Defined in: datagrid/src/grid.ts:1261
Reorder the visible columns. Accepts a permutation of the currently-visible ids; the new order is spliced back into the full order so hidden columns keep their anchor slots. A non- permutation (unknown id, wrong length, duplicate) is ignored.
Parameters
ids
string[]
The visible ids in their new order.
Returns
void
setColumnVisible()
setColumnVisible(
id,visible):void
Defined in: datagrid/src/grid.ts:1352
Show or hide a column. A hidden column is omitted from the visible order/layout but stays addressable by id for sort/filter (its sort/filter state is retained and reappears when shown). An unknown id is ignored.
Parameters
id
string
The column id.
visible
boolean
false to hide, true to show.
Returns
void
setColumnWidth()
setColumnWidth(
id,w):void
Defined in: datagrid/src/grid.ts:1311
Set a column's explicit width, clamped to the column's [minWidth, maxWidth]. An unknown id is ignored. The override makes the column apportion as a fixed width.
Parameters
id
string
The column id.
w
number
The requested width in cells (clamped).
Returns
void
setFilter()
setFilter(
columnId,filter):void
Defined in: datagrid/src/grid.ts:1048
Set (or replace) a column's filter. The quick-filter row and the popups both call this. An unknown columnId is ignored — never added to the model and never forwarded to a push-down setFilter.
Parameters
columnId
string
The column to filter.
filter
The filter condition to apply.
Returns
void
setFrozen()
setFrozen(
left,right):void
Defined in: datagrid/src/grid.ts:1399
Re-pin the frozen columns at runtime. Sets the left and right frozen panels to the given ids (an unknown or hidden id is ignored by the partition); the panels rebuild reactively. The over-pin guard still applies — pinning wider than the viewport peels the innermost frozen column back to the scrolling center (and, when every column would be frozen, the freeze is dropped with one dev warning so the grid stays scrollable). Freeze is otherwise construction-only; this is what lets applyVariant restore it.
Parameters
left
string[]
Column ids to pin to the left panel, in order.
right
string[]
Column ids to pin to the right panel, in order.
Returns
void
Example
import { signal } from '@jsvision/ui';
import { column, fromRows, EditableDataGrid } from '@jsvision/datagrid';
interface Row { id: number; name: string }
const rows = signal<Row[]>([{ id: 1, name: 'Ada' }]);
const columns = [
column({ id: 'id', title: 'Id', value: (r: Row) => r.id }),
column({ id: 'name', title: 'Name', value: (r: Row) => r.name }),
column({ id: 'actions', title: '', value: () => '…' }),
];
const grid = new EditableDataGrid<Row>({ columns, source: fromRows(rows, { rowKey: (r) => r.id }) });
grid.setFrozen(['id'], ['actions']); // id pinned left, actions pinned right
grid.setFrozen([], []); // clear all freezingsetLayout()
setLayout(
patch):void
Defined in: ui/dist/view/view.d.ts:246
Change some of this view's layout props and request a reflow — the only way to write layout. Props the patch does not name are kept, and the reflow happens for you.
The merge is shallow, deliberately: size and rect are replaced whole rather than merged field-by-field. That is what makes a variant swap correct — going from {kind:'fixed',cells:1} to {kind:'fr',weight:1} must not leave a stale cells behind. The cost is that per-side padding cannot be patched one side at a time; pass the whole padding value.
Two behaviours worth knowing:
- An explicit
undefinedresets that prop to its layout default.setLayout({ size: undefined })makes the view auto-sized again, andsetLayout({ position: 'flow' })puts an absolutely-placed view back in the flow (its now-unusedrectis simply ignored). - Do not call it in a constructor of a class that subclasses may extend. A base constructor body runs before a subclass's
override readonly layout = {…}field initializer, and that initializer installs a fresh object, so the call would be erased. Call it after construction, or fromonMount.
Reflowing an unmounted view is a no-op, so calling it before mount is safe.
Parameters
patch
Partial<LayoutProps>
The layout props to change; anything omitted is preserved.
Returns
void
Example
import { Group } from '@jsvision/ui';
const panel = new Group();
panel.setLayout({ direction: 'col', padding: 1 });
// Later — `direction` and `padding` survive; once `panel` is mounted this also reflows:
panel.setLayout({ size: { kind: 'fr', weight: 1 } });Inherited from
Group.setLayout
sort()
sort():
SortKey[]
Defined in: datagrid/src/grid.ts:1037
The current sort model. Reactive — reading it inside an effect re-runs when the sort changes.
Returns
SortKey[]
The ordered SortKey[] (empty when unsorted); the first key is the primary.
sortBy()
sortBy(
columnId,dir?):void
Defined in: datagrid/src/grid.ts:992
Sort by a single column (a plain header click / the primary API). With an explicit dir, sets exactly that key. Without dir: an unsorted or secondary column becomes the sole ascending key; re-issuing it on the sole sorted column cycles its direction (asc → desc → cleared). An unknown columnId is ignored (never forwarded to a source query).
Parameters
columnId
string
The column to sort by.
dir?
Optional explicit direction; omit to toggle/cycle.
Returns
void
toggleRow()
toggleRow(
key):void
Defined in: datagrid/src/grid.ts:1933
Toggle a row's membership under the selection mode (multi adds/removes; single replaces), and make it the range anchor.
Parameters
key
The row key to toggle.
Returns
void
totalCount()
totalCount():
number
Defined in: datagrid/src/grid.ts:1098
The pre-filter row count. Reactive. On the client path this is the true total; on a push-down source it reflects whatever source.length() reports (see filteredCount).
Returns
number
The source's row count.