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.

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.

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 can only ever produce an HTML string, 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 each row card in this layout
  columns: ColumnDefinitionsList;
}

type ResponsiveColumnDefinitions = ColumnDefinitionsList | ResponsiveColumnDefinition[];

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 and records the width that layout needs. When the container is resized, it 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.