Docs
Getting started
FreeGrid is a framework-free TypeScript grid with thin React and Vue wrappers. Install the core package, or the wrapper for your framework.
npm i @freegridjs/core
# React
npm i @freegridjs/core @freegridjs/react
# Vue
npm i @freegridjs/core @freegridjs/vueGive the grid a container with a height, import the stylesheet once, and pass columns and rows. Only the rows on screen are rendered, so the data size barely matters.
import { createGrid } from '@freegridjs/core';
import '@freegridjs/core/styles.css';
const grid = createGrid(document.getElementById('grid'), {
columns: [
{ field: 'name', header: 'Name', pinned: 'left' },
{ field: 'country', header: 'Country', filter: 'set' },
{ field: 'joined', header: 'Joined', type: 'date' },
{ field: 'total', header: 'Total', type: 'number', format: '#,##0' },
],
data: rows,
});Use it from a CDN
No build step? Load the bundle from npm through unpkg with a script tag. It exposes a global FreeGrid and includes all seven languages. @0 follows the newest 0.x release; pin an exact version such as @freegridjs/[email protected] in production. The same files are on jsDelivr: replace unpkg.com with cdn.jsdelivr.net/npm.
<link rel="stylesheet" href="https://unpkg.com/@freegridjs/core@0/dist/cdn/freegrid.css">
<script src="https://unpkg.com/@freegridjs/core@0/dist/cdn/freegrid.min.js"></script>
<div id="grid" style="height: 480px"></div>
<script>
const grid = FreeGrid.createGrid(document.getElementById('grid'), {
columns: [{ field: 'name' }, { field: 'total', type: 'number', format: '#,##0' }],
data: [{ name: 'Kim', total: 1200 }, { name: 'Lee', total: 3400 }],
locale: 'ko', // all 7 languages are bundled
});
</script><link rel="stylesheet" href="https://unpkg.com/@freegridjs/core@0/dist/cdn/freegrid.css">
<div id="grid" style="height: 480px"></div>
<script type="module">
import { createGrid } from 'https://unpkg.com/@freegridjs/core@0/dist/cdn/freegrid.esm.js';
createGrid(document.getElementById('grid'), { columns, data });
</script>Column definitions
Columns are plain objects. The column id is id if you set one, otherwise field; sorting, filters and column state all refer to columns by that id.
const columns = [
{ field: 'id', header: 'ID', type: 'number', format: '0', width: 80, pinned: 'left' },
{ field: 'name', header: 'Name', flex: 1, minWidth: 160 },
{ field: 'price', header: 'Price', type: 'number', format: 'currency:KRW' },
{ field: 'qty', header: 'Qty', type: 'number' },
// computed column
{ id: 'amount', header: 'Amount', type: 'number', format: '#,##0', valueGetter: row => row.price * row.qty },
{ field: 'status', header: 'Status', filter: 'set', cellClass: p => `status-${p.value}` },
];| Name | Type | Description |
|---|---|---|
field | string | Property of the row object shown in this column. |
id | string | Column id. Defaults to field; required when there is no field. |
header | string | Header text. Defaults to field. |
type | 'text' | 'number' | 'date' | 'boolean' | Drives alignment, formatting, sorting and the default filter. |
format | string | Intl options | Number: '#,##0.00', '0.0%', 'currency:KRW', 'integer'. Date: 'date', 'datetime', 'time', 'short', 'medium', 'long'. |
width / minWidth / maxWidth | number | Pixel widths. Default width 120, min 40. |
flex | number | Share of the leftover width. Resizing turns it into a fixed width. |
pinned | 'left' | 'right' | Keep the column visible while scrolling horizontally. |
hide | boolean | Start hidden. Users can show it from the column chooser. |
align | 'left' | 'center' | 'right' | Cell alignment. Numbers default to right. |
sortable | boolean | Default true. |
resizable | boolean | Default true. |
filter | 'text' | 'number' | 'date' | 'set' | false | Filter UI in the column menu. Default depends on type. |
comparator | (a, b, rowA, rowB) => number | Custom sort order. |
valueGetter | (row) => unknown | Computed value, e.g. quantity × price. Used for display, sort, filter and summaries. |
renderer | (params) => string | HTMLElement | Custom cell content. Strings are inserted as HTML — escape untrusted data. |
cellClass | string | (params) => string | Extra CSS class on cells. |
children | ColumnDef[] | Makes this a column group header. |
merge | boolean | (a, b, rowA, rowB) => boolean | Merge consecutive rows with the same value into one tall cell. |
wrapHeaderText | boolean | Let a long header label wrap. |
chooser | boolean | false keeps the column out of the column chooser. |
lockVisible | boolean | Users cannot hide this column. |
editable | boolean | Allow editing and pasting (needs field). |
editor | { type: 'select', options } | { type: 'textarea' } | (params) => editor | Editor for this column. options can be a function of the row (dependent selects). |
required | boolean | Reject blank values. |
validate | (value, row) => true | string | Return a message to reject a value. |
Grid options
| Name | Type | Description |
|---|---|---|
columns | ColumnDef[] | Required. Column definitions. |
data | object[] | Rows. |
getRowId | (row) => string | Stable id; keeps selection across setData. |
rowSelection | 'single' | 'multiple' | Adds a checkbox column and click selection. |
rowHeight / headerHeight | number | Pixels. Default follows the font size (36 / 40 at 13px). |
theme | string | 'light', 'dark', 'board', 'erp', 'excel', 'classic' or your own. |
fontSize / fontFamily | number / string | Grid font. Row heights follow the size. |
locale | string | LocalePack | UI language, e.g. 'ko' or an imported pack. Default: the browser's language. |
sideBar | boolean | { open } | Dock the Columns panel on the right. |
summary | SummaryOptions | Summary rows. See Summary rows. |
rangeSelection | boolean | Excel-style cell ranges by drag, Shift+click, Shift+arrows, Ctrl+A. Default true. |
statusBar | boolean | Row counts plus count/sum/average/min/max of the selected cells. |
fillHandle | boolean | Drag the selection corner to fill editable cells. Default true. |
pinnedTopRows / pinnedBottomRows | Row[] | Rows fixed above or below the scrolling rows. |
findBar / wrapHeaderText | boolean | Ctrl+F find bar (default true); wrap all header labels. |
keymap | Record<string, action | false> | Remap or disable keys, e.g. { Enter: false, 'Ctrl+E': 'edit' }. |
contextMenu | false | (params) => items | false keeps the browser menu; a function customizes the right-click menu. |
Data and row ids
Rows are ordinary objects. Without getRowId rows are identified by position, so replacing the data clears the selection. With it, the selection survives setData as long as the ids still exist.
const grid = createGrid(el, {
columns,
data: rows,
getRowId: row => String(row.id), // keeps selection and focus stable across setData
});
grid.setData(await fetch('/api/orders').then(r => r.json()));
grid.getData(); // rows as passed in
grid.getDisplayedRowCount(); // rows after filtersSorting
Click a header to cycle ascending, descending and unsorted. Shift-click (or Ctrl/⌘-click) adds the column as another sort key; a small number shows its order. Empty values always sort last. Text uses the active language's collation, so Korean, accents and numbers inside text sort naturally.
grid.setSort([{ colId: 'country', dir: 'asc' }, { colId: 'total', dir: 'desc' }]);
grid.getSort();
grid.setSort([]); // clear
// custom order
{ field: 'grade', comparator: (a, b) => ORDER.indexOf(a) - ORDER.indexOf(b) }Filtering
Each column's ⋮ menu holds a filter that matches its type: text (contains, equals, starts/ends with, blank…), number (=, ≠, <, ≤, >, ≥, between, blank), date (equals, before, after, between) and set (a searchable checklist of the column's values). Text matching ignores case. A filled filter icon marks filtered columns.
grid.setFilter('name', { type: 'text', op: 'contains', value: 'kim' });
grid.setFilter('total', { type: 'number', op: 'between', value: 1000, valueTo: 5000 });
grid.setFilter('joined', { type: 'date', op: 'after', value: '2025-01-01' });
grid.setFilter('country', { type: 'set', values: ['Japan', 'South Korea'] });
grid.setFilter('name', null); // clear one
grid.setQuickFilter('kim seoul'); // every word must match some visible column
grid.on('filterChange', e => console.log(e.filters));Pinning and column groups
Pinned columns stay visible while the middle section scrolls horizontally. Users can pin and unpin from the column menu. Columns with children become group headers, nested as deep as you like; a group split across pinned sections shows its header in each.
const columns = [
{ field: 'name', header: 'Name', pinned: 'left' },
{ header: 'Revenue 2026', children: [
{ header: 'First half', children: [{ field: 'q1' }, { field: 'q2' }] },
{ header: 'Second half', children: [{ field: 'q3' }, { field: 'q4' }] },
] },
{ field: 'total', header: 'Total', pinned: 'right' },
];Column customization
Users can drag headers to reorder, drag header edges to resize, and use the column menu to autosize, hide, pin or reset columns. Choose columns opens a chooser with search, select all, the group tree and drag-to-reorder; the same panel can be docked on the right with sideBar. Store getColumnState() to remember each user's layout.
const grid = createGrid(el, {
columns: [
{ field: 'id', lockVisible: true }, // cannot be hidden
{ field: 'internalCode', chooser: false }, // not listed in the chooser
...rest,
],
data,
sideBar: { open: false }, // docked Columns panel (true = closed, { open: true } = open)
});
grid.openColumnChooser();
grid.setColumnVisible('email', false);
grid.autoSizeColumns(); // all columns
grid.autoSizeColumns(['name']); // one column
// save / restore the user's layout
localStorage.setItem('layout', JSON.stringify(grid.getColumnState()));
grid.applyColumnState(JSON.parse(localStorage.getItem('layout')));
grid.resetColumnState();Summary rows
Summary rows show totals, averages and other aggregates. Put them at the top or bottom; keep them pinned outside the scroll area, or let them scroll with the data. They recalculate when data, filters or (with scope: 'selected') the selection change, and use each column's format unless a cell sets its own.
createGrid(el, {
columns,
data,
summary: {
position: 'bottom', // 'top' | 'bottom'
pinned: true, // true: fixed; false: scrolls with the rows
scope: 'filtered', // 'filtered' | 'all' | 'selected'
rows: [
{ label: 'Total', columns: { qty: 'sum', amount: 'sum', id: 'count' } },
{ label: 'Average', columns: { amount: { agg: 'avg', format: '#,##0.0' } } },
{ columns: {
amount: { agg: 'max', prefix: 'max' },
country: values => `${new Set(values).size} countries`, // custom
} },
],
},
});
grid.setSummary({ position: 'top', rows: [...] }); // change at runtime
grid.setSummary(null); // remove
grid.getSummaryValues(); // [{ qty: 1234, amount: 99000, id: 50 }, …]sum,avg,min,maxuse numeric values and skip blanks;min/maxalso compare dates.countis the number of rows in scope.- A function receives the column's values and the rows; return a number to have it formatted, or a string to show as is.
- The row
labelappears in the first visible column without an aggregate in that row.
Editing
Mark a column editable: true and users can edit its cells: double-click, press Enter or F2, or just start typing. Enter saves and moves down, Tab saves and moves to the next editable cell, Esc cancels. Booleans toggle with Space or a double-click.
The editor follows the column type: text, numbers (1,234 is accepted), dates and booleans. Use a select editor for a fixed list. When its options is a function of the row, you get dependent selects such as cities by country. required and validate keep bad values out; the editor stays open with a message until the value is fixed.
Every edit, paste, insert and removal is tracked and can be undone with Ctrl+Z. Changed cells get a small corner mark. When you're ready to save, read getModifiedRows() or the column-level getChanges(), send them to your server, then call commitChanges().
const COUNTRIES = { KR: ['Seoul', 'Busan'], JP: ['Tokyo', 'Osaka'] };
const grid = createGrid(el, {
columns: [
{ field: 'id', type: 'number' }, // read-only
{ field: 'name', editable: true, required: true },
{ field: 'qty', type: 'number', editable: true, validate: v => v >= 0 || 'Must be 0 or more' },
{ field: 'country', editable: true, editor: { type: 'select', options: Object.keys(COUNTRIES) } },
{ field: 'city', editable: true, editor: { type: 'select', options: row => COUNTRIES[row.country] } },
{ field: 'memo', editable: true, editor: { type: 'textarea' } },
{ field: 'active', type: 'boolean', editable: true }, // Space / double-click toggles
],
data,
});
grid.addRows([{ name: 'New' }], 0);
grid.removeSelectedRows();
grid.undo(); grid.redo();
// send only what changed
const { created, updated, deleted } = grid.getModifiedRows();
await save({ created, updated, deleted, cells: grid.getChanges() });
grid.commitChanges(); // or grid.revertChanges()Spreadsheet tools
Set merge: true on a column and consecutive rows with the same value become one tall cell, which is handy for reports grouped by region or team. Sort by that column first. statusBar: true adds a bar that shows row counts and the count, sum, average, minimum and maximum of the selected cells. Drag the small square at the corner of a selection to fill editable cells: numbers and dates continue their step, text ending in a number counts up, and anything else repeats.
Use pinnedTopRows and pinnedBottomRows for rows that should never scroll away, such as targets or references. Ctrl+F opens a find bar inside the grid; find() does the same from code.
createGrid(el, {
columns: [
{ field: 'region', merge: true }, // identical neighbours become one tall cell
{ field: 'team', merge: (a, b, ra, rb) => a === b && ra.region === rb.region },
{ field: 'q1', type: 'number', editable: true, wrapHeaderText: true },
],
data: rowsSortedByRegion,
statusBar: true, // "1,000 rows · Count 12 Sum 48,000 Average 4,000 …"
fillHandle: true, // drag the corner: 1, 2 → 3, 4, 5 …; Mon → copies; "item 7" → "item 8"
pinnedTopRows: [{ region: 'Target', q1: 50000 }],
});
grid.find('Seoul'); // highlights matches, focuses the first; Ctrl+F opens the same as a bar
grid.findNext();Copy, paste and right-click
Select cells like in Excel: drag across them, Shift-click, use Shift with the arrow keys, or press Ctrl+A. Ctrl+C copies the range in a format Excel and Google Sheets understand: numbers stay numbers, dates become YYYY-MM-DD. Ctrl+V pastes cells copied from Excel starting at the selected cell. A single copied value fills the whole selected range.
Pasting only changes columns with editable: true, so ids and computed columns stay safe. Values are converted to the column type: 1,234, ₩12,000, (5) and 12% become numbers; 2026. 3. 5. and 2026년 3월 5일 become dates. Values that can't be converted are skipped and counted in the paste event.
Right-click a cell for Copy, Copy with headers, Paste, autosize, hide and pin. Right-click a header for the column menu. Turn ranges off with rangeSelection: false, or bring back the browser menu with contextMenu: false.
const grid = createGrid(el, {
columns: [
{ field: 'id', type: 'number' }, // read-only
{ field: 'name', editable: true }, // paste allowed
{ field: 'qty', type: 'number', editable: true }, // "1,234", "(5)", "12%" are parsed
{ field: 'due', type: 'date', editable: true }, // "2026-03-05", "2026. 3. 5." …
],
data,
rangeSelection: true, // default: drag / Shift+click / Shift+arrows / Ctrl+A
contextMenu: p => [
...p.defaultItems, // Copy, Paste, Pin, Hide, …
'separator',
{ label: 'Open order', action: () => open(p.row) },
],
});
grid.on('cellValueChanged', e => save(e.row)); // persist edits
grid.on('paste', e => console.log(e.changed, 'cells changed'));
grid.setRange({ start: { rowIndex: 0, colId: 'name' }, end: { rowIndex: 9, colId: 'qty' } });
grid.copySelection({ headers: true }); // TSV, also written to the clipboard
grid.pasteText('Kim 1,234
Lee 56');The menu's Paste item reads the clipboard, which some browsers block or ask about. Ctrl+V always works because it uses the browser's own paste event.
Row selection
With rowSelection the grid adds a checkbox column. Click selects a row, Ctrl/⌘-click toggles, Shift-click selects a range, the header checkbox selects every filtered row, and Space toggles the focused row.
const grid = createGrid(el, { columns, data, rowSelection: 'multiple', getRowId: r => r.id });
grid.on('selectionChange', e => console.log(e.selected.length));
grid.getSelectedRows();
grid.selectAll(); // selects the filtered rows
grid.deselectAll();Keyboard
Click a cell or tab into the grid, then:
| Key | Action |
|---|---|
← ↑ → ↓ | Move the focused cell. |
Tab / Shift+Tab | Next / previous cell, wrapping rows; leaves the grid at the ends. |
Home / End | First / last column. |
Ctrl+Home / Ctrl+End | First / last cell. |
PageUp / PageDown | One screen up / down. |
Shift + ← ↑ → ↓ / Home / End / Page | Extend the cell range. |
Ctrl+A | Select every cell. |
Ctrl+C / Ctrl+V | Copy to / paste from Excel (TSV). |
Ctrl+F | Find in the grid. |
Shift+F10 / ContextMenu | Open the right-click menu. |
Enter / F2 / typing | Start editing an editable cell. |
Enter / Tab / Esc (editing) | Save and move down / save and move right / cancel. |
Delete | Clear editable cells. |
Ctrl+Z / Ctrl+Y | Undo / redo. |
Space | Toggle the focused row’s selection. |
Esc | Close the column menu or chooser. |
Formatting and renderers
Numbers and dates are formatted with the browser's Intl APIs in the grid language, so 1234.5 becomes 1,234.5 in English and 1.234,5 in German. Use renderer for anything else; it gets value, formatted, row, rowIndex and column.
{ field: 'total', type: 'number', format: '#,##0' } // 1,234
{ field: 'rate', type: 'number', format: '0.0%' } // 12.5%
{ field: 'price', type: 'number', format: 'currency:KRW' } // ₩12,000
{ field: 'price', type: 'number', format: { maximumSignificantDigits: 3 } } // Intl options
{ field: 'joined', type: 'date', format: 'long' } // 2026년 3월 5일 (ko)
// element renderer
{ field: 'status', renderer: p => {
const b = document.createElement('span');
b.className = `badge badge-${p.value}`;
b.textContent = p.formatted;
return b;
} }A renderer that returns a string is inserted as HTML. Escape anything that comes from users, or return an element.
Themes and fonts
Built-in themes: light, dark, and four simple Korean-style themes — board (bulletin board: thick top rule, horizontal lines), erp (every cell bordered, compact), excel (gridlines, green focus) and classic (navy header). Font size and family are one option each; row heights follow the size unless you set them.
createGrid(el, { columns, data, theme: 'erp', fontSize: 12, fontFamily: 'Pretendard, sans-serif' });
grid.setTheme('board');
grid.setFont({ size: 14 });
grid.setFont({ family: null }); // back to the theme fontMake your own theme
/* any class named fg-theme-<name> is a theme */
.fg-theme-brand {
--fg-font: "Pretendard", sans-serif;
--fg-font-size: 13px;
--fg-bg: #fff; --fg-fg: #1d2433; --fg-muted: #6b7385;
--fg-header-bg: #f2f5fa; --fg-header-fg: #1d2433;
--fg-border: #d9dfe8; --fg-row-border: #edf0f5;
--fg-col-line: inset -1px 0 #edf0f5;
--fg-row-odd: #fff; --fg-row-hover: #f5f8ff; --fg-row-selected: #e6eeff;
--fg-accent: #3056d3; --fg-focus: #3056d3;
--fg-header-text-align: center; --fg-header-label-flex: 1 1 auto;
}| Variable | Kind | Controls |
|---|---|---|
--fg-font / --fg-font-size | font | Font family and size. |
--fg-bg / --fg-fg / --fg-muted | color | Background, text and secondary text. |
--fg-header-bg / --fg-header-fg / --fg-header-weight | color / weight | Header colors and weight. |
--fg-border / --fg-row-border | color | Outer border and row lines. |
--fg-col-line | box-shadow | Vertical cell lines, e.g. 'inset -1px 0 #ddd'. Default none. |
--fg-row-odd / --fg-row-hover / --fg-row-selected | color | Zebra, hover and selected rows. |
--fg-accent / --fg-focus | color | Buttons, sort icons and the focused cell. |
--fg-radius / --fg-cell-px | length | Corner radius and cell padding. |
--fg-header-text-align / --fg-top-border | keyword / border | Center header labels; thick top rule. |
Languages
English is built in. Korean, Simplified Chinese, Japanese, Spanish, French and German are separate imports so you only ship what you use. Without a locale option the grid picks the browser language when that pack is registered, otherwise English.
import ko from '@freegridjs/core/locales/ko';
createGrid(el, { columns, data, locale: ko });
// or register once and use codes
import { registerLocale } from '@freegridjs/core';
import ja from '@freegridjs/core/locales/ja';
registerLocale(ja);
grid.setLocale('ja');
// override a few messages
createGrid(el, { columns, data, locale: { ...ko, noRows: '조회 결과가 없습니다' } });React
@freegridjs/react exports <FreeGrid>. Every grid option is a prop and every event is an on… prop. The ref is the grid API. Changing data, columns, theme, locale, font or summary updates the grid; keep those objects stable with useMemo.
import { FreeGrid } from '@freegridjs/react';
import type { GridApi } from '@freegridjs/core';
import '@freegridjs/core/styles.css';
export function Orders({ rows }) {
const grid = useRef<GridApi>(null);
const columns = useMemo(() => [...], []); // keep props stable
return (
<FreeGrid
ref={grid}
columns={columns}
data={rows}
rowSelection="multiple"
theme="erp"
locale="ko"
summary={summary}
onCellClick={e => console.log(e.row)}
onSelectionChange={e => setCount(e.selected.length)}
style={{ height: 520 }}
/>
);
}
// grid.current?.setSort([{ colId: 'total', dir: 'desc' }])Vue
@freegridjs/vue exports <FreeGrid> for Vue 3.3+. Events are kebab-case (@cell-click, @selection-change…), and the component ref exposes getApi().
<script setup lang="ts">
import { FreeGrid } from '@freegridjs/vue';
import '@freegridjs/core/styles.css';
const grid = ref();
const sort = () => grid.value.getApi().setSort([{ colId: 'total', dir: 'desc' }]);
</script>
<template>
<FreeGrid
ref="grid"
:columns="columns"
:data="rows"
row-selection="multiple"
theme="erp"
locale="ko"
:height="520"
:summary="summary"
@cell-click="e => console.log(e.row)"
@selection-change="e => (count = e.selected.length)"
/>
</template>API reference
createGrid(element, options) returns this API. Calls after destroy() do nothing.
| Method | Returns | Description |
|---|---|---|
setData(rows) | void | Replace all rows. |
getData() | Row[] | Current rows (unfiltered, unsorted). |
setColumns(defs) | void | Replace column definitions. |
getColumnState() / applyColumnState(state) | ColumnState[] | Save and restore order, width, visibility and pinning. |
resetColumnState() | void | Back to the column definitions. |
setColumnVisible(colId, visible) | void | Show or hide a column. |
autoSizeColumns(colIds?) | void | Fit widths to header and visible cells. |
openColumnChooser() / closeColumnChooser() | void | Floating column chooser. |
toggleSideBar(open?) | void | Open or close the docked Columns panel. |
setSort(items) / getSort() | SortItem[] | e.g. [{ colId: 'total', dir: 'desc' }]. |
setFilter(colId, model | null) / getFilterModel() | FilterModel | Set or clear one column filter. |
setQuickFilter(text) | void | Search all visible columns. |
getSelectedRows() / selectAll() / deselectAll() | Row[] | Selection helpers. selectAll selects the filtered rows. |
setSummary(options | null) / getSummaryValues() | object[] | Change summary rows; read raw totals. |
getRange() / setRange(range | null) | GridRange | Read or set the selected cell range. |
copySelection({ headers? }) | string | Copy the range as Excel TSV and return it. |
pasteText(text) | { changed, skipped } | Paste TSV/Excel text at the range or focused cell. |
startEdit(rowIndex, colId) / stopEdit(cancel?) | boolean / void | Open or close the editor. |
addRows(rows, index?) / removeRows(rows | fn) / removeSelectedRows() | Row[] | Insert or remove rows (tracked, undoable). |
getModifiedRows() / getChanges() / hasChanges() | object | Created/updated/deleted rows and column-level diffs. |
commitChanges() / revertChanges() | void | Accept changes as the new baseline, or undo all of them. |
undo() / redo() / canUndo() / canRedo() | void / boolean | Undo history for edits, pastes and row changes. |
fillRange(target) | void | Fill from the selection into a larger range (series aware). |
find(text) / findNext() / findPrevious() / clearFind() | number / void | Highlight and step through matching cells. |
setPinnedRows({ top?, bottom? }) | void | Change pinned rows. |
getDisplayedRowCount() | number | Rows after filtering. |
scrollToRow(index) | void | Scroll a displayed row into view. |
setTheme(name) | void | Switch theme. |
setFont({ size?, family? }) | void | Change font; family null restores the theme font. |
setLocale(codeOrPack) | void | Switch UI language. |
on(event, handler) | () => void | Subscribe; returns an unsubscribe function. |
destroy() | void | Remove the grid and its listeners. |
Events
| Event | Payload | When |
|---|---|---|
cellClick / cellDoubleClick | { row, rowIndex, colId, value, event } | A data cell was clicked. |
selectionChange | { selected: Row[] } | Selected rows changed. |
sortChange | { sort } | Sort changed. |
filterChange | { filters } | A column filter changed. |
columnResize | { colId, width } | Resize or autosize finished. |
columnMove | { colId, toIndex } | A column was dragged to a new position. |
columnVisible | { colId, visible } | A column was shown or hidden. |
rangeChange | { range } | The cell range changed. |
cellValueChanged | { row, rowIndex, colId, oldValue, newValue } | A paste changed a cell. |
paste | { changed, skipped } | A paste finished. |
editStart / editStop | { rowIndex, colId, committed? } | An editor opened or closed. |
validationFailed | { rowIndex, colId, value, message } | An edited value was rejected. |
rowsAdded / rowsRemoved | { rows } | Rows were inserted or removed. |
focusChange | { rowIndex, colId } | The focused cell moved. |