npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lightfastgrid/vue

v0.2.0

Published

Vue package for LightFastGrid, a JavaScript data grid for large client-side datasets.

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/vue
pnpm add @lightfastgrid/vue
yarn 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/core

The 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 only
  • immutableRows — selects setRows vs setRowsImmutable
  • 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.

  • getRowId
  • rowPinning
  • initialSortModel
  • suppressRowVirtualization
  • suppressColumnVirtualization

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:

  1. Custom row actions (cellRenderers, kind: 'actions', mode: 'custom')
  2. Header actions (headerRenderers)
  3. Grid overlays (overlays, including live handle.setOverlays)
  4. 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

License

MIT. See LICENSE.