Getting Started
Installation
npm install @dynamicforms/vue-gridIn your main.ts:
import { DynamicFormsVueGrid } from '@dynamicforms/vue-grid';
import '@dynamicforms/vue-grid/styles.css';
const app = createApp(MyApp);
app.use(router);
app.use(vuetify);
// makes <DfGrid> available globally
app.use(DynamicFormsVueGrid, { registerComponents: true });
// skip global component registration; still registers v-longpress
// app.use(DynamicFormsVueGrid);If you prefer to register <DfGrid> locally in individual components:
import { DfGrid } from '@dynamicforms/vue-grid';See DynamicFormsVueGridOptions for the full set of install options.
Basic Usage
<template>
<df-grid
:columns="columns"
:records="records"
key-field="id"
/>
</template>
<script setup lang="ts">
import { createColumn, DfGrid } from '@dynamicforms/vue-grid';
const columns = [
createColumn('id', 'ID', 'int'),
createColumn('name', 'Name', 'plain', { sortable: true }),
createColumn('email', 'Email', 'email'),
];
const records = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
];
</script>
<style>
.df-record-grid {
display: grid;
grid-template-columns: minmax(2em, 4em) 1fr 1fr;
gap: 0.25em;
}
</style>The <style> block above is required, not optional polish
The template and script alone render every cell stacked on its own line, one per row of text, not a table — the grid has no fallback layout of its own. .df-record-grid has to be display: grid with a track per column before anything lines up. See Card layout CSS below for why.
<df-grid> needs a definite height from somewhere
Rows are virtualized against the grid's own scroll viewport, so <df-grid> (or an ancestor of it) needs a bounded height — a fixed height, a vh/% value backed by a sized ancestor, or being a flex/grid item that fills available space (flex: 1 1 auto; min-height: 0, say). Leave every ancestor unconstrained and the body scroller collapses to zero height instead, with nothing left to window rows against; <df-grid> logs a console warning when this happens, but the fix is still on your side of the boundary — give it height.
Card layout CSS
The grid's own layout comes from your own stylesheet, as set above — make .df-record-grid a grid and give it a base track list, one track per column; the grid reads the body's actual (natively-resolved) widths and republishes them onto the header for you. .df-record-grid is the marker every place that lays out a record's fields carries — the real scrolling body, the header, and the filter row alike — so this one declaration covers all three, instead of just the body. Each cell carries its column's fieldName as a CSS class, so you can target individual columns by name once the base grid is in place:
.df-grid.cell.id { text-align: right; }See Card layout CSS for how column widths are measured and published, and Grid structure for the full section layout diagram.
Translation
The grid draws a small number of English strings of its own, each under a key naming what it says rather than its English text. The library ships no translations and selects no locale: the application passes its translation function to translateStrings once, with the namespace that holds the grid's keys in its translations.
The authoritative list is src/table/translations.ts - the object passed to createTranslatable there is the whole catalogue:
| Key | English default | Where it appears |
|---|---|---|
Loading | Loading… | Summary bar, while loading is true |
NoData | No data | Summary bar, when records is empty |
FilterColumn | Filter {column}... | Filter row's default placeholder, when a filterable column has none of its own |
CancelSelectionMode | Cancel selection mode | Selection status bar's cancel icon tooltip |
InvertSelection | Invert selection | Selection status bar's invert icon tooltip |
SelectionCountSelected | {count} items selected | Selection status bar, in 'selection' mode |
SelectionCountExcluded | {count} items excluded | Selection status bar, in 'exclusion' mode |
ActiveFilters | Active filters: {count} | Status bar's default statusBar slot content |
RecordCount | {count} records | Status bar's default statusBar slot content, when the total is unknown |
RecordCountOfTotal | {count} of {total} records | Status bar's default statusBar slot content |
NullValue | null | A cell's content when its value is null/undefined and no nullHandler says otherwise |
With vue-i18n:
import { formatParams } from '@dynamicforms/translatable';
import { translateStrings } from '@dynamicforms/vue-grid';
const { t, n } = i18n.global;
// formats `{count}` for the locale before t substitutes it
translateStrings(formatParams(t, (value) => (typeof value === 'number' ? n(value) : value)), 'grid');{ "grid": { "NoData": "Ni podatkov", "ActiveFilters": "Aktivni filtri: {count}" } }- A key is looked up as
grid.<Key>; without a namespace, as<Key>. - The grid passes each placeholder's value to the translation function, which substitutes it. A translation uses the placeholder names of the English default.
- A key the translation function returns unchanged has no translation and reads as the English default.
- The grid calls the translation function on every render, so a grid on screen follows a locale switch of vue-i18n's
twithout anothertranslateStringscall. A translation function over non-reactive translations needs anothertranslateStringscall after they change.
translate(key, params?) returns the current text of one of these keys, for an application drawing its own status bar or summary with the grid's strings.
The @dynamicforms/translatable readme describes the translation function, the resolution order and a translation function written without an i18n library.
Next steps
The example above covers a plain, read-only grid. From here:
- Sorting —
sortable: trueon any column - Filtering —
filterable: trueon a column,:show-filter-row="true"on the grid - Responsive layouts — multiple column sets that switch automatically with container width
- Row selection — shift+click, long-press, and
#groupActionsbatch actions, built in
The Cookbook has copy-pasteable recipes for common tasks beyond a plain data column — clickable action icons, a dedicated selection checkbox column, responsive card layouts, and more.
