Appearance
Component API
The Vue and the React component share the same core: columns, options and the grid API are identical. They differ in how state is bound and how content is customized (slots vs. render props). Use the framework switch in the navigation bar to show the API of your framework.
vue
<Datagrid
:columns="columns"
:rows="rows"
:options="options"
v-model:selectedItems="selected"
@cell-value-changed="save"
/>Datagrid is a generic component: the row type is inferred from rows and used for columns, options and the event payloads.
tsx
<Datagrid
columns={columns}
rows={rows}
options={options}
selectedItems={selected}
onSelectedItemsChange={setSelected}
onCellValueChanged={save}
/>Datagrid is generic: the row type is inferred from rows and used for columns, options, the callbacks and the render props.
Props
| Prop | Type | Description |
|---|---|---|
columns | ColumnConfig<T>[] | column definitions (required), see column options |
rows | T[] | undefined | data; undefined shows the loading indicator |
options | GridOptions<T> | see grid options |
pinnedTopRows | T[] | rows pinned below the header |
pinnedBottomRows | T[] | rows pinned to the bottom |
theme | "light" | "dark" | "auto" | color theme |
events | Partial<CoreDelegate> | low level callbacks of the core |
className, style | React only: class and style of the root element (Vue: class / style attributes) |
All props are reactive. options and columns are watched deeply, rows shallowly.
All props can change at any time. columns and options are compared by value (functions by their source), so inline objects don't reset the grid – but memoizing them with useMemo or defining them outside of the component saves work.
Binding state
| Model | Type | Description |
|---|---|---|
v-model:rows | T[] | updated after editing and pasting |
v-model:selectedItems | ItemUid[] | ids of the selected rows |
v-model:selectedCells | { item: ItemUid; column: string }[] | selected cells |
v-model:expandedItems | ItemUid[] | expanded tree and group rows |
v-model:sortedColumns | { column: string; asc: boolean }[] | sort model |
v-model:columnFilter | { column: string; value: unknown }[] | column filters, see filter values |
v-model:globalFilter | unknown | quick filter |
v-model:columnGroups | string[] | ids of the grouped columns |
v-model:pageIndex | number | current page (zero based) |
Each piece of state can optionally be controlled: pass the value and its change callback. Without the value the grid manages the state itself (uncontrolled); the callback alone can be used to observe changes.
| Value prop | Change callback | Type |
|---|---|---|
rows | onRowsChange | T[] – called with a new array after editing and pasting |
selectedItems | onSelectedItemsChange | ItemUid[] |
selectedCells | onSelectedCellsChange | { item: ItemUid; column: string }[] |
expandedItems | onExpandedItemsChange | ItemUid[] |
sortedColumns | onSortedColumnsChange | { column: string; asc: boolean }[] |
columnFilter | onColumnFilterChange | { column: string; value: unknown }[], see filter values |
globalFilter | onGlobalFilterChange | unknown |
columnGroups | onColumnGroupsChange | string[] |
pageIndex | onPageIndexChange | number |
Controlled means controlled
A controlled value without a change callback (or with a callback that ignores the value) is re-applied after every user interaction – e.g. columnFilter={[]} without onColumnFilterChange makes the filter row read-only. This is the usual React behavior of controlled inputs.
Events
| Event | Payload |
|---|---|
ready | api: Core – the grid is initialized |
cell-click | { event, row, column, data, value } |
cell-dblclick | { event, row, column, data, value } |
cell-contextmenu | { event, row, column, data, value } |
header-contextmenu | { event, column } |
cell-value-changed | { item, column, data, oldValue, newValue, source } |
selection-change | { keys, rows, cells } |
sort-change | { column, asc }[] |
filter-change | { column, value }[] |
group-change | string[] |
page-change | PaginationState |
column-resize | Column |
row-drop | { row, target, position } – see row dragging |
state-change | GridState |
| Prop | Payload |
|---|---|
onReady | api: Core – the grid is initialized |
onCellClick | { event, row, column, data, value } |
onCellDoubleClick | { event, row, column, data, value } |
onCellContextMenu | { event, row, column, data, value } – call event.preventDefault() to suppress the built-in context menu |
onHeaderContextMenu | { event, column } |
onCellValueChanged | { item, column, data, oldValue, newValue, source } |
onSelectionChange | { keys, rows, cells } |
onPageChange | PaginationState |
onColumnResize | Column |
onRowDrop | { row, target, position } – see row dragging |
onStateChange | GridState |
events | Partial<CoreDelegate> – low level callbacks of the core |
Customizing content
| Slot | Props | Description |
|---|---|---|
cell-<columnId> / cell | value, text, row, data, column, setValue, api | cell content |
header-<columnId> / header | column, text, api | header content |
filter-<columnId> / filter | column, value, setValue, api | floating filter |
editor-<columnId> / editor | value, setValue, submit, cancel, row, data, column, api | editor |
detail | row, data, api | detail row content |
group | group, key, text, count, column, api | group row content |
toolbar | api | above the grid |
footer | api | below the grid |
empty | – | no rows |
loading | – | loading indicator |
overlay | api | layer on top of the grid |
statusbar | items, info, api | content of the status bar |
| Prop | Parameters | Description |
|---|---|---|
cellRenderers | Record<columnId | "*", (params) => ReactNode>, params: value, text, row, data, column, setValue, api | cell content |
headerRenderers | Record<columnId | "*", (params) => ReactNode>, params: column, text, api | header content |
filterRenderers | Record<columnId | "*", (params) => ReactNode>, params: column, value, setValue, api | floating filter |
renderDetail | { row, data, api } | detail row content |
renderGroup | { group, key, text, count, column, api } | group row content |
renderStatusBar | { items, info, api } | content of the status bar |
renderEmpty | – | no rows |
renderLoading | – | loading indicator |
toolbar | ReactNode | (api) => ReactNode | above the grid |
footer | ReactNode | (api) => ReactNode | below the grid |
overlay | ReactNode | (api) => ReactNode | layer on top of the grid |
Custom editors are components set with the column option editComponent, see custom editors.
Renderers are called while rendering the grid – keep them cheap and define them outside of the component or with useMemo when they don't depend on state.
Methods
Access them with a template ref:
ts
const grid = ref<InstanceType<typeof Datagrid>>();
grid.value?.exportCsv();
grid.value?.core.sortColumn("name", "asc");| Member | Description |
|---|---|
core / api | the complete grid API |
exportCsv(params?) | download csv |
getDataAsCsv(params?) | csv text |
selectAll(), deselectAll() | |
expandAll(), collapseAll() | |
getState(), setState(state) | |
refresh() | re-apply sorting and filters, reload server side data |
autosizeColumns(columns?) | |
focus() | move the browser focus into the grid |
undo(), redo() | undo / redo the last cell change |
Access the API with a ref:
tsx
const grid = useRef<DatagridHandle>(null);
grid.current?.exportCsv();
grid.current?.api.sortColumn("name", "asc");
<Datagrid ref={grid} ... />| Member | Description |
|---|---|
api | the complete grid API |
exportCsv(params?) | download csv |
getDataAsCsv(params?) | csv text |
selectAll(), deselectAll() | |
expandAll(), collapseAll() | |
getState(), setState(state) | |
refresh() | re-apply sorting and filters, reload server side data |
autosizeColumns(columns?) | |
focus() | move the browser focus into the grid |
undo(), redo() | undo / redo the last cell change |
The API is also passed to onReady.
Headless hook
useDatagrid(columns, rows, options) (a composable in Vue, a hook in React) uses the grid logic without the grid UI – see headless usage.