Skip to content

Column Definitions ​

Columns are defined using createColumn() and passed to <DfGrid> via the columns prop. The grid supports both flat (single-layout) and responsive (multi-layout) column definitions.

createColumn() ​

typescript
function createColumn<R extends keyof RendererOptionsMap>(
  fieldName: string,
  label: string,
  renderer?: R,
  otherOptions?: Omit<ColumnDefinition<R>, 'fieldName' | 'label' | 'renderer'>,
): ColumnDefinition<R>
ParameterTypeDescription
fieldNamestringProperty name on the row data object, read as a direct property access — dotted paths are not resolved. Also used as a CSS class on cells.
labelstringColumn header label.
rendererkeyof RendererOptionsMapCell renderer to use. Defaults to 'plain'. See Cell Renderers.
otherOptionsobjectAdditional column options (see ColumnDefinition below).

ColumnDefinition ​

typescript
interface ColumnDefinition<R extends keyof RendererOptionsMap = 'plain'> {
  fieldName: string;
  label: string;
  renderer?: R;
  rendererOptions?: RendererOptionsMap[R]; // renderer-specific options
  sortable?: Sortable;                     // see Sorting
  filterable?: Filterable;                 // see Filtering
  cssClass?: string;                       // additional CSS class(es) on cells
}

createColumn() sets sortable: true on the column it builds; a sortable key in otherOptions overrides it. A ColumnDefinition written as a plain object literal has no such default, and a column without sortable cannot be sorted.

cssClass is set on the column's header cell as well as its body cells. A header cell lays out its label and sorting indicator as a flex row, so text-align does not move them; the classes text-right, text-end and text-center align them to the end or the centre of the header cell.

Example ​

typescript
import { createColumn } from '@dynamicforms/vue-grid';

const columns = [
  createColumn('id', 'ID', 'int', { cssClass: 'text-right' }),
  createColumn('title', 'Title', 'plain', { sortable: true }),
  createColumn('rating', 'Rating', 'float', {
    sortable: { direction: 'desc', nulls: 'last' },
    filterable: { fieldType: 'number' },
    rendererOptions: { locale: { locale: 'en-US', localeOptions: { minimumFractionDigits: 1, maximumFractionDigits: 1 } } },
  }),
];

Custom renderer functions ​

renderer accepts a function instead of a registry name, for a column whose content isn't a formatted field value at all:

typescript
type CellRendererTransformer = (
  value: any,
  rowValue: RowValue,
  options: CellOptionsInternal,
) => RenderableValue;

The function is called directly instead of looking up a renderer in the registry, and takes full ownership of the cell's main content — no transform or type-specific formatting runs, since there is no registry renderer in the loop at all. It still composes with preRender/postRender: whatever the function returns is wrapped exactly the way a built-in renderer wraps its own output. An element it returns is the cell itself, stretched to its grid area; see Custom renderers.

This is the same CellRendererTransformer type setCellRenderer() uses to replace a named renderer application-wide (see Cell Renderers); passing one directly as renderer instead scopes it to a single column. transform produces the value the column's renderer formats, never a component with its own event handlers, so it cannot express a cell whose whole content is interactive — this is why the option exists. See A column that isn't tied to a single field in the Cookbook for a worked example.

Responsive layouts ​

To define multiple layouts that activate at different container widths, pass an array of ResponsiveColumnDefinition objects:

typescript
interface ResponsiveColumnDefinition {
  name?: string;     // optional name; defaults to cssClass value
  cssClass: string;  // CSS class applied to the shared body grid in this layout
  columns: ColumnDefinitionsList;
  rows?: number;     // grid rows this layout's cards occupy per record; default 1
}

type ResponsiveColumnDefinitions = ColumnDefinitionsList | ResponsiveColumnDefinition[];

rows matters only for a layout that stacks more than one row of fields per record (a card layout, not a single-line one) — see Card layout CSS for how it plugs into --row-base in your own CSS.

The grid decides whether the array is responsive by looking at its first element: an element carrying name or cssClass together with columns marks the whole array as a list of layouts. Every entry must end up with a non-empty name — name, or cssClass when name is omitted — otherwise the grid throws column definition <idx> must have a name or cssClasses assigned and non-empty.

The grid renders a hidden shadow grid for each layout from the first secondaryShadowCount records in display order and records the width that layout needs. A layout is measured again when more records are available to sample than its width was recorded from, so a grid that starts empty and receives its first page later is measured from that page rather than from its header alone. Records that change without growing the sample keep the recorded width; reMeasureLayouts() measures every layout again. When the container is resized or a recorded width changes, the grid emits update:activeColumns with the name of the widest layout whose recorded width still fits the container. If no layout fits, the active layout stays as it is.

The value of activeColumns is matched against the layout name — name when given, otherwise cssClass. When activeColumns is unset, or names no existing layout, the first layout in the array is used. A flat column list is treated as a single layout named default with an empty cssClass.

typescript
import { createColumn, filterColumns } from '@dynamicforms/vue-grid';
import type { ResponsiveColumnDefinitions } from '@dynamicforms/vue-grid';

const allColumns = [
  createColumn('id',      'ID',      'int'),
  createColumn('name',    'Name',    'plain'),
  createColumn('country', 'Country', 'plain'),
  createColumn('email',   'Email',   'email'),
];

const columnsResponsive: ResponsiveColumnDefinitions = [
  { cssClass: 'wide',   columns: allColumns },
  { cssClass: 'medium', columns: filterColumns(allColumns, [0, 1, 3]) },
  { cssClass: 'narrow', columns: filterColumns(allColumns, [1]) },
];
vue
<df-grid
  v-model:active-columns="activeLayout"
  :columns="columnsResponsive"
  :records="records"
  key-field="id"
/>

Only the active column list changes between layouts — the grid placement of each cell within the card is your own CSS, keyed off the layout's cssClass. See the Cookbook for a worked example, including collapsing a wide layout into a stacked, single-column one.

filterColumns() ​

A helper to select a subset of columns by index or field name:

typescript
function filterColumns(
  columns: ColumnDefinitionsList,
  selectors: (number | string | { [fieldName: string]: number })[],
): ColumnDefinitionsList

Selectors can be:

  • number — picks column at that index
  • string — picks the first column with that fieldName
  • { fieldName: occurrence } — picks the column with that fieldName at index occurrence (0-based) among all columns sharing the name; only the first entry of the object is read

The returned list follows the order of the selectors, not the order of the columns. A column selected twice appears twice, and a selector that matches nothing is dropped.

useColumns() ​

typescript
function useColumns(props: GridProps, gridId: symbol)

The composable <DfGrid> uses to resolve the columns prop down to a single active layout. gridId is a symbol identifying the grid instance; it is what the numeric renderers register their per-column formatting state under, and what releases it when the grid unmounts. The returned members are all computed refs:

MemberDescription
activeName of the active layout: the activeColumns prop, or the first layout's name when the prop is unset.
builtColumnsAll layouts, each carrying name, cssClass and columns.
activeColumnsDefinitionThe entry of builtColumns that is currently active.
namename of the active layout.
cssClasscssClass of the active layout; '' for a flat column list.
columnsThe active layout's column list.

Released under the MIT License.