Skip to content
Kappa
Data Grid
@dicehub/kappav0.4.2

Data Grid

A typed, accessible grid for interactive records and very large data sets.

8 records
Actions
Atlas migrationOwen HartReview18 min ago82%
Beacon auditSofia BellPaused1 hr ago71%
Cinder catalogNoah ParkActive3 hr ago91%
Delta archiveIris KingReviewYesterday86%
Ember indexLuca ReedActiveYesterday93%
<script setup lang="ts">
import { ref } from "vue";
import {
  Badge,
  DataGrid,
  Input,
  type DataGridColumn,
  type DataGridSort,
} from "@dicehub/kappa";

type RecordRow = { id: string; name: string; owner: string; status: string };
const rows = ref<RecordRow[]>([]);
const query = ref("");
const selected = ref<string[]>([]);
const sorting = ref<DataGridSort[]>([]);
const rowToValue = (row: RecordRow) => row.id;
const columns: DataGridColumn<RecordRow>[] = [
  { id: "name", header: "Name", accessorKey: "name", pinned: "start", width: 220 },
  { id: "owner", header: "Owner", accessorKey: "owner", width: 160 },
  { id: "status", header: "Status", accessorKey: "status", width: 120 },
];
</script>

<template>
  <DataGrid
    v-model:query="query"
    v-model:selected-value="selected"
    v-model:sorting="sorting"
    :columns="columns"
    :rows="rows"
    :row-to-value="rowToValue"
    selection-mode="multiple"
    paginated
  >
    <template #toolbar>
      <Input v-model="query" aria-label="Search records" />
      <DataGrid.ColumnVisibility />
    </template>
    <template #cell-status="{ value }"><Badge>{{ value }}</Badge></template>
    <template #footer><DataGrid.Pagination /></template>
  </DataGrid>
</template>

Installation

import { DataGrid } from "@dicehub/kappa";
// Or use the component entry point:
import { DataGrid } from "@dicehub/kappa/components/data-grid";

Data Grid uses TanStack Table and TanStack Virtual internally. Its public columns, state, events, and slots are Kappa types.

Usage

Use Data Grid when the application owns interactive data operations. Use Table for static semantic tables and small custom layouts.

Each row needs a stable value. Define columns once, outside render loops. Named cell-* slots support badges, buttons, links, and application-owned inputs without coupling the grid to a data model.

Replace the rows array when data changes, for example rows.value = rows.value.map(updateRow). Changing a field or one array element in place is not supported because the row engine caches accessor values.

Standard mode keeps natural row height. Virtual mode targets large flat data sets, requires a fixed rowHeight, and shows a small loader while its visible row window changes. Do not use multiline cells in virtual mode.

Composition

Typical part hierarchy
DataGrid.Root <div>
├── toolbar slot (optional)
│   ├── application controls
│   └── DataGrid.ColumnVisibility (optional)
├── viewport
│   └── semantic table with grid keyboard behavior
│       ├── sortable and resizable headers
│       └── standard or virtual rows
└── footer slot (optional)
    └── DataGrid.Pagination (optional)

DataGrid.Context exposes the same reactive state to custom controls.

DataGrid.Root renders the grid and provides reactive state to its slots. Put DataGrid.ColumnVisibility in the toolbar slot and DataGrid.Pagination in the footer slot. Use DataGrid.Context when a custom control needs the same state.

Examples

100,000 rows

Virtual mode keeps a small, overscanned row window in the DOM. It requires a fixed row height and a constrained viewport height.

Preparing 100,000 rows
Actions
Loading data
<DataGrid
  :columns="columns"
  :rows="oneHundredThousandRows"
  :row-to-value="rowToValue"
  mode="virtual"
  height="32rem"
  :row-height="28"
  :overscan="10"
  compact
/>

Server-controlled state

This deterministic server simulation owns search, sorting, paging, and the total row count. No live service is required.

8 records
Actions
Atlas migrationOwen HartReview18 min ago82%
Beacon auditSofia BellPaused1 hr ago71%
Cinder catalogNoah ParkActive3 hr ago91%
<DataGrid
  v-model:page="page"
  v-model:page-size="pageSize"
  v-model:sorting="sorting"
  v-model:query="query"
  :columns="columns"
  :rows="currentServerPage"
  :row-count="totalCount"
  :row-to-value="rowToValue"
  manual-filtering
  manual-pagination
  manual-sorting
  paginated
  @page-change="loadPage"
  @sorting-change="loadPage"
  @query-change="loadPage"
/>

Row-click selection

Keep selection without a leading checkbox column. Clicking a row toggles its selected state.

8 records
Actions
Atlas migrationOwen HartReview18 min ago82%
Beacon auditSofia BellPaused1 hr ago71%
Cinder catalogNoah ParkActive3 hr ago91%
Delta archiveIris KingReviewYesterday86%
Ember indexLuca ReedActiveYesterday93%
<DataGrid
  v-model:selected-value="selected"
  :columns="columns"
  :rows="rows"
  :row-to-value="rowToValue"
  selection-mode="multiple"
  :show-selection-column="false"
/>

Compact

Compact mode reduces the row rhythm for information-dense applications.

8 records
Actions
Atlas migrationOwen HartReview18 min ago82%
Beacon auditSofia BellPaused1 hr ago71%
Cinder catalogNoah ParkActive3 hr ago91%
Delta archiveIris KingReviewYesterday86%
Ember indexLuca ReedActiveYesterday93%
<DataGrid compact :columns="columns" :rows="rows" :row-to-value="rowToValue" />

Multiline rows

Standard mode keeps native table flow, so rich cells can increase the row height.

8 records
Actions
Atlas migrationContains a longer description that wraps naturally in standard mode without a fixed row height.
Owen HartReview18 min ago82%
Beacon auditContains a longer description that wraps naturally in standard mode without a fixed row height.
Sofia BellPaused1 hr ago71%
Cinder catalogContains a longer description that wraps naturally in standard mode without a fixed row height.
Noah ParkActive3 hr ago91%
Delta archiveContains a longer description that wraps naturally in standard mode without a fixed row height.
Iris KingReviewYesterday86%
Ember indexContains a longer description that wraps naturally in standard mode without a fixed row height.
Luca ReedActiveYesterday93%
<DataGrid :columns="columns" :rows="rows" :row-to-value="rowToValue">
  <template #cell-name="{ row }">
    <div><strong>{{ row.name }}</strong><p>{{ row.description }}</p></div>
  </template>
</DataGrid>

Loading, empty, and error

Use complete asynchronous states without replacing the grid shell.

Actions
Loading data
Actions
No results
Actions
<DataGrid :columns="columns" :rows="[]" :row-to-value="rowToValue" loading />
<DataGrid :columns="columns" :rows="[]" :row-to-value="rowToValue" />
<DataGrid :columns="columns" :rows="[]" :row-to-value="rowToValue" :error="loadError" />

Client and server behavior

  • Client mode applies query matching, column filters, sorting, and page slicing to rows.
  • Manual flags keep the matching operation in the application. Pass the current page plus the full rowCount.
  • Paging is one-based in Kappa. The adapter handles engine indexes internally.
  • Selection uses stable row values and remains valid when the current page changes.
  • Set showSelectionColumn to false for row-click selection without checkboxes. Use selectionMode="none" when selection is not needed.
  • Column resizing is enabled by default. Drag a resize edge, use Left or Right Arrow from its keyboard focus, or press Enter to restore its initial width. Shift changes the keyboard step.

Accessibility

The component uses semantic table elements with grid behavior. Give every instance an accessible name. Arrow keys move between cells. Home and End move across a row. Control plus Home or End moves to the first or last cell. Page Up and Page Down move by one viewport. Enter or F2 enters an interactive cell; Escape returns focus to the cell. Tab leaves the grid instead of visiting every cell control.

Sorting buttons expose aria-sort. Selection uses labeled Kappa checkboxes. Loading sets aria-busy; failures use an alert.

API Reference

DataGrid.Root

PropTypeDefaultDescription
rowsreadonly T[]—Rows for the current client data set or server page.
columnsDataGridColumn<T>[]—Kappa-owned column definitions.
rowToValue(row: T) => string—Stable row identifier used for selection and virtualization.
direction"ltr" | "rtl"inheritedPointer and keyboard resize direction. CSS direction is detected when omitted.
mode"standard" | "virtual""standard"Natural-height or fixed-row virtual rendering.
selectionMode"none" | "single" | "multiple""none"Row selection behavior.
showSelectionColumnbooleantrueShow the leading checkbox column when selection is enabled.
sorting / defaultSortingDataGridSort[][]Controlled sorting or its uncontrolled initial value.
selectedValue / defaultSelectedValuestring[][]Controlled selection or its uncontrolled initial value.
query / filtersstring / Record<string, unknown>"" / {}Client filter state. Use manualFiltering for server data.
paginatedbooleanfalseEnable page slicing and pagination context.
page / pageSize / rowCountnumber1 / 25 / rows.lengthOne-based controlled paging state.
manualFiltering / manualSorting / manualPaginationbooleanfalseKeep the matching data operation in the application.
height / rowHeight / overscanCSS height / number / number"28rem" / 36 / 8Virtual viewport geometry.
loading / errorboolean / unknownfalse / undefinedAsynchronous state.

Columns

DataGridColumn<T> contains id, header, accessorKey or accessor, and optional width, minimum, maximum, alignment, sorting, filtering, search, resizing, hiding, formatting, and pinning settings.

Slots

toolbar, footer, loading, empty, error, header, header-{id}, cell, and cell-{id}.

Events

Each controlled state emits update:* plus a named change event. Activation emits cellActivate or rowActivate. Selection change includes selected values and the matching loaded rows.

Exports

DataGrid, DataGridRoot, DataGridPagination, DataGridColumnVisibility, DataGridContext, and Kappa-owned public types.