@lightfastgrid/vue
v0.2.0
Published
Vue package for LightFastGrid, a JavaScript data grid for large client-side datasets.
Maintainers
Readme
LightFastGrid for Vue
@lightfastgrid/vue integrates LightFastGrid with Vue 3. It is MIT licensed
and supports the declared Vue peer range ^3.5.0 (Vue 3.5 and later 3.x;
not Vue 2 or Vue 4).
Install
Install from npm when the package release is available:
npm install @lightfastgrid/vuepnpm add @lightfastgrid/vueyarn add @lightfastgrid/vue@lightfastgrid/core is installed as a runtime dependency. Public TypeScript
declarations are included; no separate @types package is needed.
Quick start
<script setup lang="ts">
import {
LightFastGrid,
type VueLightFastGridProps,
} from '@lightfastgrid/vue';
type Order = { id: string; customer: string; total: number };
const rows: Order[] = [
{ id: 'order-1001', customer: 'Acme', total: 1200 },
{ id: 'order-1002', customer: 'Globex', total: 850 },
];
const columns: VueLightFastGridProps['columns'] = [
{ field: 'customer', headerName: 'Customer' },
{ field: 'total', headerName: 'Total' },
];
function getRowId(row: { id?: unknown }): string {
return String(row.id);
}
</script>
<template>
<LightFastGrid
:rows="rows"
:columns="columns"
:get-row-id="getRowId"
:height="420"
:accessibility="{ ariaLabel: 'Orders' }"
/>
</template>getRowId must return a unique, stable id for every row. Do not derive it from
the row's current position.
Sizing and theme CSS
The grid fills its parent. Set height on LightFastGrid (a number means CSS
pixels), or give the parent a real height and let the default height: 100%
fill that parent.
Host class, style, id, and data-* fall through onto the single host
element. Do not pass className.
A blank or clipped grid is usually a sizing problem, not a data problem.
The Vue package loads the default Core theme CSS. Do not import
@lightfastgrid/core/themes/default.css again. Use a CSS-aware bundler such
as Vite; raw Node imports without a CSS loader are not supported.
Data updates and API readiness
The wrapper observes top-level prop reference or scalar changes, not nested
mutations. Keep large row datasets in a plain array or shallowRef; replace
the array when the application changes rows. Use immutableRows for
stable-id snapshot updates, or issue Core transactions through the component
handle. The wrapper does not deep-watch, clone, or own row objects.
For commands, type a component ref as VueLightFastGridHandle and use it after
@grid-ready (or after nextTick() following mount). Unmounting disposes the
Grid; retained handle methods then throw LFG_VUE_GRID_NOT_READY.
If application code imports ColumnDef or other types directly from
@lightfastgrid/core, declare Core as a direct dependency. This matters under
pnpm's strict dependency resolution:
pnpm add @lightfastgrid/vue @lightfastgrid/coreThe package ships ESM, CommonJS, and TypeScript declarations. Vue SFCs are compiled by the consumer's build tooling, not at package runtime.
Capabilities and limits
- Core provides virtualized rows and columns, sorting, filtering, selection, editing, pagination, CSV export, keyboard navigation, and eligible Worker work.
- Vue custom content is supported only in row actions, header actions, grid overlays, and cell-shell overlays. Ordinary cells stay Core-rendered.
- SSR renders an empty host; rows are client-rendered. This is not a Nuxt module or server-rendered grid-cell implementation.
- The wrapper does not deep-watch datasets, copy rows, or retain historical renderer leases. No comparative performance claim is made here.
- A shared Core queued-scroll issue can immediately close a row-action menu when clicking an offscreen trigger during horizontal auto-scroll.
Props
LightFastGrid accepts native Vue props. Observational grid callbacks are
emits, not onXxx callback props. The TypeScript prop type is
VueLightFastGridProps.
Live inputs update the existing Grid when the top-level prop reference or
scalar changes. Nested mutation of an existing rows array or options object is
not observed. There is no catch-all updateOptions.
Wrapper-only fields that never enter Core:
height— host style onlyimmutableRows— selectssetRowsvssetRowsImmutable- fallthrough host attrs
Reserved Core fields that remain unused: getParentId, mode, rowModelType.
Optional Core booleans such as pagination, loading, and floatingFilters
stay undefined when omitted so Core defaults apply.
Initial-only inputs
These are applied at Grid construction. Changing them later does not update the
live Grid and logs a one-time development warning. Remount with a new Vue key
to apply a new value.
getRowIdrowPinninginitialSortModelsuppressRowVirtualizationsuppressColumnVirtualization
Runtime sort, pin, and related commands still go through the handle.
Events
One emit per Core GridEventCallbacks key. gridReady has no payload. Import
payload types from @lightfastgrid/core when you need them.
| Emit | Template listener | Payload |
| --- | --- | --- |
| gridReady | @grid-ready | none |
| columnResized | @column-resized | LightFastGridColumnResizedEvent |
| sortChanged | @sort-changed | LightFastGridSortChangedEvent |
| filterChanged | @filter-changed | LightFastGridFilterChangedEvent |
| selectionChanged | @selection-changed | LightFastGridSelectionChangedEvent |
| columnSelectionChanged | @column-selection-changed | LightFastGridColumnSelectionChangedEvent |
| columnOrderChanged | @column-order-changed | LightFastGridColumnOrderChangedEvent |
| columnPinChanged | @column-pin-changed | LightFastGridColumnPinChangedEvent |
| rowPinChanged | @row-pin-changed | LightFastGridRowPinChangedEvent |
| columnVisibilityChanged | @column-visibility-changed | LightFastGridColumnVisibilityChangedEvent |
| rowOrderChanged | @row-order-changed | LightFastGridRowOrderChangedEvent |
| cellValueChanged | @cell-value-changed | LightFastGridCellValueChangedEvent |
| paginationChanged | @pagination-changed | LightFastGridPaginationChangedEvent |
| focusedCellChanged | @focused-cell-changed | LightFastGridFocusedCellChangedEvent |
| cellShellAction | @cell-shell-action | LightFastGridCellShellActionEvent |
| rowDataUpdated | @row-data-updated | LightFastGridRowDataUpdatedEvent |
| quickFilterChanged | @quick-filter-changed | LightFastGridQuickFilterChangedEvent |
| quickSearchPendingChanged | @quick-search-pending-changed | LightFastGridQuickSearchPendingChangedEvent |
| asyncTransactionsFlushed | @async-transactions-flushed | LightFastGridAsyncTransactionsFlushedEvent |
| csvExportProgress | @csv-export-progress | CsvExportProgress |
| csvExportCompleted | @csv-export-completed | CsvExportResult |
| csvExportCancelled | @csv-export-cancelled | { taskId: number } |
| csvExportError | @csv-export-error | { taskId: number; error: unknown } |
There is no update:rows emit and no synthesized selection v-model.
Synchronous edit hook
onBeforeCellEditCommit is a function prop, not an emit. It runs
synchronously inside Core. It is not listed in the 23 emits above.
Wait for gridReady or nextTick() after mount before calling the handle.
After changing props, wait for nextTick() before issuing commands that depend
on that change.
<script setup lang="ts">
import type { LightFastGridBeforeCellEditCommitEvent } from '@lightfastgrid/core';
import { useTemplateRef } from 'vue';
import {
LightFastGrid,
type VueLightFastGridHandle,
} from '@lightfastgrid/vue';
type Order = { id: string; customer: string; total: number };
const rows: Order[] = [{ id: 'order-1001', customer: 'Acme', total: 1200 }];
const columns = [
{ field: 'customer', headerName: 'Customer' },
{ field: 'total', headerName: 'Total' },
];
const gridRef = useTemplateRef<VueLightFastGridHandle>('grid');
function onGridReady(): void {
gridRef.value?.setSelectedRowIds(['order-1001']);
}
function onBeforeCellEditCommit(
event: LightFastGridBeforeCellEditCommitEvent,
): void {
void event.rowId;
}
</script>
<template>
<LightFastGrid
ref="grid"
:rows="rows"
:columns="columns"
:get-row-id="(row) => String(row.id)"
:on-before-cell-edit-commit="onBeforeCellEditCommit"
:height="420"
@grid-ready="onGridReady"
/>
</template>Handle readiness and errors
defineExpose publishes VueLightFastGridHandle: Core GridApi except
setOverlays, which accepts Vue overlay options.
There is no getInstance, mount, or destroy on the handle. Before
readiness and after disposal, every method throws Error with
code: 'LFG_VUE_GRID_NOT_READY'. Core method errors propagate unchanged.
Type the ref with useTemplateRef<VueLightFastGridHandle>('grid').
Rows, mutation, and update ownership
Keep datasets in a plain array behind shallowRef or a replaced binding. Do
not wrap the row list in reactive(). The wrapper does not deep-watch or copy
rows.
In-place mutation of objects already given to the Grid is not detected. Replace
the rows array (or call transactions) when application state changes.
<script setup lang="ts">
import { shallowRef } from 'vue';
import { LightFastGrid } from '@lightfastgrid/vue';
type Order = { id: string; customer: string; total: number };
const columns = [
{ field: 'customer', headerName: 'Customer' },
{ field: 'total', headerName: 'Total' },
];
const rows = shallowRef<Order[]>([
{ id: 'order-1001', customer: 'Acme', total: 1200 },
]);
function replaceSnapshot(): void {
rows.value = rows.value.map((row) => ({ ...row, total: row.total + 1 }));
}
</script>
<template>
<div>
<button type="button" @click="replaceSnapshot">Replace rows</button>
<LightFastGrid
:rows="rows"
:columns="columns"
:get-row-id="(row) => String(row.id)"
:immutable-rows="true"
:height="420"
/>
</div>
</template>immutableRows keeps stable ids and uses Core's immutable setter. Application
code owns whether the next snapshot is a new array.
Transactions
applyTransaction / applyTransactionAsync return Core results. Assign
result.rows back to your shallowRef when the next prop snapshot should match
the Grid. Unchanged rows references do not replay setRows.
<script setup lang="ts">
import { shallowRef, useTemplateRef } from 'vue';
import {
LightFastGrid,
type VueLightFastGridHandle,
} from '@lightfastgrid/vue';
type Order = { id: string; customer: string; total: number };
const columns = [
{ field: 'customer', headerName: 'Customer' },
{ field: 'total', headerName: 'Total' },
];
const rows = shallowRef<Order[]>([
{ id: 'order-1001', customer: 'Acme', total: 1200 },
]);
const gridRef = useTemplateRef<VueLightFastGridHandle>('grid');
function addRow(): void {
const result = gridRef.value?.applyTransaction({
add: [{ id: 'order-1002', customer: 'Globex', total: 850 }],
});
if (result !== undefined) {
rows.value = result.rows as Order[];
}
}
</script>
<template>
<div>
<button type="button" @click="addRow">Add row</button>
<LightFastGrid
ref="grid"
:rows="rows"
:columns="columns"
:get-row-id="(row) => String(row.id)"
:height="420"
/>
</div>
</template>Renderers
Ordinary cells stay Core-rendered. Vue content is limited to four surfaces:
- Custom row actions (
cellRenderers,kind: 'actions',mode: 'custom') - Header actions (
headerRenderers) - Grid overlays (
overlays, including livehandle.setOverlays) - Cell-shell overlays (
cellShellOverlays)
Action-menu mode is passed through unchanged. Renderer render() may return a
vnode or { node, cleanup }. The wrapper copies the grid's appContext, so
app provides, global components, and plugins resolve. Child inject() does
not see provide() from ancestors of LightFastGrid. Closures from the
parent SFC setup are the supported pattern.
Cleanup unmounts Vue content before Core reuses the host. Registry replacement does not refresh an already-open lease. Do not promise async setup or Suspense inside popups that must focus synchronously.
<script setup lang="ts">
import { h } from 'vue';
import {
LightFastGrid,
type VueCellRendererRegistry,
type VueCellShellOverlayRegistry,
type VueGridOverlaysOptions,
type VueHeaderRendererRegistry,
} from '@lightfastgrid/vue';
type Order = { id: string; customer: string; status: string };
const rows: Order[] = [{ id: 'order-1001', customer: 'Acme', status: 'open' }];
const columns = [
{
field: 'customer',
headerName: 'Customer',
headerActions: [{ id: 'inspect', rendererKey: 'inspect' }],
},
{
field: 'status',
headerName: 'Status',
cellShell: { kind: 'button' as const, overlay: { key: 'status' } },
},
{
field: 'actions',
headerName: '',
cellKind: 'actions' as const,
actionsKey: 'row',
actionTrigger: { icon: '⋯' },
},
];
const cellRenderers: VueCellRendererRegistry = {
row: {
kind: 'actions',
mode: 'custom',
render: (ctx) =>
h('button', { type: 'button', onClick: () => ctx.close() }, ctx.rowId),
},
};
const headerRenderers: VueHeaderRendererRegistry = {
inspect: {
kind: 'header-action',
mode: 'custom',
render: (ctx) =>
h('button', { type: 'button', onClick: () => ctx.close() }, ctx.field),
},
};
const overlays: VueGridOverlaysOptions = {
loading: { text: 'Loading' },
noRows: { text: 'No orders' },
};
const cellShellOverlays: VueCellShellOverlayRegistry = {
status: {
kind: 'cell-shell-overlay',
render: (ctx) => h('p', String(ctx.formattedValue)),
},
};
</script>
<template>
<LightFastGrid
:rows="rows"
:columns="columns"
:get-row-id="(row) => String(row.id)"
:cell-renderers="cellRenderers"
:header-renderers="headerRenderers"
:overlays="overlays"
:cell-shell-overlays="cellShellOverlays"
:height="420"
/>
</template>Unmounting LightFastGrid destroys the Grid generation and drains renderer
leases. Remount creates a new generation.
Direct Core types
import type {
ColumnDef,
LightFastGridSelectionChangedEvent,
} from '@lightfastgrid/core';
import type { VueLightFastGridProps } from '@lightfastgrid/vue';
export const customerColumn: ColumnDef = {
field: 'customer',
headerName: 'Customer',
};
export const props: VueLightFastGridProps = {
columns: [customerColumn],
rows: [{ id: 'order-1001', customer: 'Acme' }],
};
export function logSelection(
event: LightFastGridSelectionChangedEvent,
): number {
return event.selectedCount;
}SSR
onMounted does not run during Vue SSR. renderToString of LightFastGrid
renders the empty host and does not construct a Grid. Client hydration or mount
creates one Grid; teardown releases it.
Supported smoke environment: Vite or vue/server-renderer. CSS remains
bundler-owned. This is not a Nuxt module and does not claim raw Node CSS
imports.
Links
- LightFastGrid website
- Core quick start (framework-neutral behavior)
- Core runtime API reference
- Repository
- Issues
- MIT license
License
MIT. See LICENSE.
