Custom Renderers
Render custom Vue 3 components inside grid cells and headers, including badges, charts, action menus, and any other interactive UI you need to embed today.
Customize how cells and headers are rendered.
Interactive Demo
Cell Renderers
gp-grid for Vue accepts two renderer styles and you can mix them freely in the same grid:
h()render functions — great for small inline renderers- Single-File Components — great for anything with template syntax, scoped styles, or reusable logic
Mixing both in one grid
<script setup lang="ts">
import { type CellRendererParams } from "@gp-grid/vue";
const props = defineProps<CellRendererParams>();
</script>
<template>
<div class="flex items-center h-full px-2">
<span
class="w-2 h-2 rounded-full mr-2"
:style="{ backgroundColor: props.value === 'Active' ? 'green' : 'red' }"
/>
{{ props.value }}
</div>
</template><script setup lang="ts">
import { Grid, type CellRendererParams, type ColumnDefinition } from "@gp-grid/vue";
import { h } from "vue";
import StatusCell from "./StatusCell.vue";
// h() render function — concise, no separate file
const SalaryRenderer = (params: CellRendererParams) => {
const value = params.value as number;
return h("div", {
class: "flex items-center justify-end h-full px-2 tabular-nums",
}, `$${value.toLocaleString()}`);
};
const columns: ColumnDefinition[] = [
{ field: "name", cellDataType: "text", width: 150 },
{
field: "status",
cellDataType: "text",
width: 120,
// SFC passed directly — gp-grid handles the component lifecycle
cellRenderer: StatusCell,
},
{
field: "salary",
cellDataType: "number",
width: 140,
// h() function for the same `cellRenderer` slot
cellRenderer: SalaryRenderer,
},
];
const data = [
{ name: "Giovanni", status: "Active", salary: 82000 },
{ name: "Luca", status: "Inactive", salary: 64000 },
];
</script>
<template>
<div style="height: 400px">
<Grid :columns="columns" :row-data="data" :row-height="36" />
</div>
</template>Both styles receive the same CellRendererParams and participate in the same virtualization pool — there is no performance penalty for mixing them.
Filters, sort comparisons, and copy-paste operate on the formatted value — the string users actually see — not the raw cell value. A cellRenderer only changes how a cell is painted; it does not change the value that powers filtering. Pair every custom renderer with a matching valueFormatter so the two stay in sync:
{
field: "salary",
cellDataType: "number",
width: 140,
cellRenderer: SalaryRenderer,
valueFormatter: (value) => `$${(value as number).toLocaleString()}`,
}Without the formatter, users filtering for "$82,000" on the Salary column would match nothing because the filter sees the raw 82000. See the full valueFormatter reference for signature, caveats, and more examples.
Registry shorthand
When the same renderer is used across multiple columns, register it once on the grid and reference it by key:
<script setup lang="ts">
import { Grid } from "@gp-grid/vue";
import StatusCell from "./StatusCell.vue";
const columns: ColumnDefinition[] = [
{ field: "name", cellDataType: "text", width: 150 },
{ field: "status", cellDataType: "text", width: 120, cellRenderer: "status" },
{ field: "manager", cellDataType: "text", width: 120, cellRenderer: "status" },
];
</script>
<template>
<Grid
:columns="columns"
:row-data="data"
:row-height="36"
:cell-renderers="{ status: StatusCell }"
/>
</template>The value of the registry map can itself be either an SFC or an h() function.
Header Renderers
Headers accept the same two styles as cells — h() functions or SFCs. The snippet below uses h() for brevity:
<script setup lang="ts">
import { type HeaderRendererParams } from "@gp-grid/vue";
import { h } from "vue";
const CustomHeader = (params: HeaderRendererParams) => {
return h("div", {
class: "flex items-center justify-between w-full h-full px-2",
}, [
h("span", { class: "font-bold" }, params.column.headerName),
params.sortDirection && h("span", {},
params.sortDirection === "asc" ? "▲" : "▼"
),
]);
};
</script>
<template>
<Grid
:columns="columns"
:row-data="data"
:row-height="36"
:header-renderer="CustomHeader"
/>
</template>Renderer Parameters
CellRendererParams
| Property | Type | Description |
|---|---|---|
value | CellValue | Current cell value |
rowData | TData | Full row data object |
column | ColumnDefinition | Column definition |
rowIndex | number | Row index |
colIndex | number | Column index |
isActive | boolean | Is the active cell |
isSelected | boolean | Is in selection range |
isEditing | boolean | Is being edited |
HeaderRendererParams
| Property | Type | Description |
|---|---|---|
column | ColumnDefinition | Column definition |
colIndex | number | Column index |
sortDirection | SortDirection | undefined | Current sort |
sortIndex | number | undefined | Multi-sort order |
sortable | boolean | Is column sortable |
filterable | boolean | Is column filterable |
hasFilter | boolean | Has active filter |
onSort | function | Trigger sort |
onFilterClick | function | Open filter popup |