Skip to content

GkDataTable

GkDataTable is a tokenized <table>-based data grid for admin views. It composes GkPagination, GkCheckbox, and GkSpinner, supports client and server data modes, optional row selection, expand rows, group headers, nested column headers, mobile stacked layout, and sticky header / fixed columns.

Smaller than Vuetify VDataTable: no internal locale/theme service; v-models are explicit; import from god-kit/vue or god-kit/vue/data.

When to use

Use for sortable, pageable lists where users need predictable keyboard targets and semantic table markup. Use GkDataTableVirtual when you must render very large row counts in a scrollport (windowed rows via @tanstack/vue-virtual). Use GkDataTableServer when the parent fetches each page from an API.

Samples cookbook

Ten interactive cookbook samples live under docs/.vitepress/components/demos/data-table/. Each sample below embeds GkDocsExample: live table plus copyable source from the same DemoGkDataTableSampleNN.vue file. See the contributor README to add more samples.

Import from god-kit/vue or god-kit/vue/data. Ensure god-kit/tokens.css and god-kit/vue.css are loaded in your app.

#SampleHighlights
1BasicMinimal columns, sort, pagination
2Searchv-model:search, filter across columns
3Multi-sortmulti-sort, several sortBy keys
4Selectionshow-select, item-value, item-selectable
5Expandshow-expand, #expanded-row
6Groupinggroup-by, #group-header
7Nested headerschildren in headers, fixed column
8Layoutfixed-header, striped, density, max-height, mobile
9Servermode="server", items-length, loading
10VirtualGkDataTableVirtual, large items

Each sample below shows the live table and copyable Vue source from the matching DemoGkDataTableSampleNN.vue (via DemoGkDataTableSampleNNDoc).

Sample 1: Basic client table

Use when you only need columns, local sort, and paging.

Sample 1: Basic client table

Use when you only need columns, local sort, and paging.

Inventory
SKU
Product
Category
Qty
Price
Status
SKU-100KeyboardInput1279In stock
SKU-200MonitorDisplay4329Low
SKU-310DockAccessories18149In stock
SKU-055WebcamAV089Backorder
SKU-420HeadsetAV25129In stock

Use v-model:search for a quick filter; omit search-keys to search all leaf columns.

Sample 2: Client search

Use v-model:search for a quick filter; omit search-keys to search all leaf columns.

Offices (client filter)
City
Subregion
Country
Pop. (M)
OsloEasternNO1.1
BergenWesternNO0.29
StockholmSödermanlandSE1
GothenburgVästra GötalandSE0.58
CopenhagenCapitalDK0.8
HelsinkiUusimaaFI0.66

Sample 3: Multi-sort

Set multi-sort so each sortable header toggles; order in sortBy is the compare order.

Sample 3: Multi-sort

Set multi-sort so each sortable header toggles; order in sortBy is the compare order.

Multi-sort (toggle several columns)
ID
Last name
First name
Dept
Role
1000LovelaceGraceEngIC
1001HopperMargaretOpsLead
1002HamiltonKatherineResearchStaff
1003JohnsonAdaDesignIC
1004LovelaceGraceEngLead

Sample 4: Row selection

show-select adds a column; v-model:selected holds itemValue keys. Use item-selectable to skip rows (for example read-only rows).

Sample 4: Row selection

show-select and v-model:selected; use item-selectable to skip rows (e.g. read-only).

Selection (Blocked rows cannot be selected)
Task
Status
Assignee
Due
Deploy APIDoneAlexApr 02
Security auditBlockedSamApr 10
Docs refreshIn progressJordanApr 14
Load testTodoRileyApr 20

Sample 5: Expandable rows

show-expand plus #expanded-row for detail panels. v-model:expanded tracks open rows by itemValue.

Sample 5: Expandable rows

show-expand plus #expanded-row; v-model:expanded tracks open rows by itemValue.

Expandable rows
Title
Owner
Status
Priority
RFC-42 AuthTeam AReviewP1
RFC-77 CacheTeam BDraftP2
RFC-91 ObservabilityTeam CApprovedP1

Sample 6: Group headers

group-by uses the first key for section breaks on the current page of items. Customize rendering with #group-header.

Sample 6: Group headers

group-by for section breaks on the current page; customize with #group-header.

Grouped by region (current page)
Service
Uptime %
Version
Region: ap (region)
API99.72.4.1
Worker99.42.4.0
Region: eu (region)
API99.92.4.1
Worker99.52.4.0
Region: us (region)
API99.82.4.1
Worker99.22.3.9

Sample 7: Nested headers and fixed column

Use children on a header for grouped titles; set fixed: true (or 'start' / 'end') on leaf columns for sticky edges inside the scroll container.

Sample 7: Nested headers and fixed column

children on headers for grouped titles; fixed on leaf columns for sticky edges.

Nested headers + fixed total column
Q1
Q2
Total
Alpha
Beta
Gamma
X
Y
102054847
128146343
722911756

Sample 8: Sticky header, stripes, density, scroll, mobile

Dense admin lists: density="compact", striped, fixed-header, and max-height so only the body scrolls. For narrow viewports, set mobile="auto" (uses useGkDisplay().mobile) or mobile to always use the stacked card layout.

Sample 8: Sticky header, stripes, density, scroll, mobile

Compact striped lists with fixed header, max-height body scroll, and mobile:auto.

ID
1
Label
Item 1
Category
Alpha
Score
60
Updated
2026-04-01
ID
2
Label
Item 2
Category
Beta
Score
67
Updated
2026-04-02
ID
3
Label
Item 3
Category
Gamma
Score
74
Updated
2026-04-03
ID
4
Label
Item 4
Category
Alpha
Score
81
Updated
2026-04-04
ID
5
Label
Item 5
Category
Beta
Score
88
Updated
2026-04-05

Sample 9: Server mode (simulated)

In server mode the table does not sort or page the full dataset locally; you pass the current page of items and total items-length. Refetch when v-model:page, v-model:items-per-page, or v-model:sort-by changes.

The default footer uses GkPagination with pagination-total-visible="7" so large server-side page counts stay compact with ellipsis instead of rendering every page button on wide viewports. Keep the default footer for the built-in page-size select and pagination controls, or set hide-default-footer and provide your own #bottom / footer slots when you need a fully custom footer.

Sample 9: Server mode (simulated)

mode="server" with items slice and items-length; loading for fetch UX.

Server mode (simulated slice)
Name
Region
Status
Row 0euok
Row 1uswarn
Row 2apidle
Row 3euok
Row 4uswarn
Row 5apidle
Row 6euok
Row 7uswarn
Row 8apidle
Row 9euok

For real APIs, replace pageItems with data from fetch and set loading around the request.

Sample 10: Virtualized body

GkDataTableVirtual window-rows large arrays with @tanstack/vue-virtual. Best for read-mostly grids; sorting and selection are usually handled separately or via headless composables.

Sample 10: Virtualized body

GkDataTableVirtual windows large item arrays with @tanstack/vue-virtual.

#
Label
Status
Category

API — GkDataTable

Props

PropTypeDefaultDescription
headersGkDataTableColumn[]requiredColumns; optional children for grouped headers
itemsRecord<string, unknown>[]requiredRows; in server mode usually the current page
mode'client' | 'server''client'client: filter/sort/paginate locally. server: show items as returned; use itemsLength for pagination
itemsLengthnumberRequired for server: total items across pages
loadingbooleanfalseShows spinner and aria-busy on the table
multiSortbooleanfalseShift-style multi-column sort (toggle adds sorts)
searchKeysstring[]Limit client search to these column keys
showSelectbooleanfalseSelection column with GkCheckbox
showExpandbooleanfalseExpand toggle + #expanded-row slot
itemValuekeyof T | (row) => unknownRow key for selection/expand; defaults to id, key, or JSON
itemSelectable(row) => booleanalways trueDisables row checkbox when false
itemsPerPageOptionsnumber[][10,25,50,100]Native <select> for page size
density'comfortable' | 'compact''comfortable'Row min-heights via tokens
stripedbooleanfalseZebra striping (disabled when groupBy is set)
hoverbooleantrueRow hover background
fixedHeaderbooleanfalseSticky <thead>
mobileboolean | 'auto'falseauto: uses useGkDisplay().mobile for stacked cards
groupBystring[]Single-level group breaks on groupBy[0] (within current page)
captionstring<caption> text
hideDefaultFooterbooleanfalseHides pagination + page size
hideDefaultHeaderbooleanfalseHides <thead>
hideSelectAllbooleanfalseHides header select-all checkbox
dir'ltr' | 'rtl''ltr'Passed to GkPagination
paginationTotalVisiblenumber | string7Max page number buttons in the default footer GkPagination
paginationShowFirstLastPagebooleanfalseShows first/last controls in the default footer GkPagination
paginationEllipsisstring'...'Ellipsis text for compact page ranges in the default footer GkPagination
maxHeightstring | numberScrollport on GkTableScroll
borderedbooleantrueOuter border on scroll wrapper

v-models

v-modelTypeDescription
searchstringClient filter string
sortBy{ key, order }[]Active sorts
pagenumberCurrent page (1-based)
itemsPerPagenumberPage size
selectedunknown[]Selected itemValue keys
expandedunknown[]Expanded itemValue keys

Events

EventPayload
click:rowrow, MouseEvent

Slots

SlotDescription
top / bottomSurround table; receive slot props (page, itemsPerPage, sortBy, pageCount, items)
header.<key>Custom header for column key — props: column, sortBy, toggleSort
item.<key>Cell — props: item, column, value
group-headerGroup row — props: groupKey, groupValue, depth
expanded-rowExpanded panel — props: item
no-dataEmpty state
body.prepend / body.appendExtra tbody rows
footer.prepend / footer.appendBeside default footer

Tokens

See Design tokens--gk-table-* variables (border, header, stripe, sticky shadows, density).


GkDataTableServer

Thin wrapper: sets mode="server" and forwards slots. Props: headers, items, itemsLength (required) plus the same v-models and slots as GkDataTable.


GkDataTableVirtual

Grid-based virtualized body for large items arrays. Props: headers, items, height (scrollport, passed as max-height), estimateSize (px, default 48), bordered, columnMinWidth. Same item.<key> slots as GkDataTable. Does not duplicate selection/sort UI — use for read-mostly huge lists or combine with headless composables.


Headless composables

Import from god-kit/vue or god-kit/vue/data: useGkTableSort, useGkTablePagination, useGkTableSelection, useGkTableExpand, useGkTableFilter, useGkTableGrouping, plus getLeafColumns, buildTheadRows, getItemKey, getRowValue.

GkDataTableServer and GkDataTableVirtual usage appears in Sample 9 and Sample 10 above.

Accessibility notes

  • Sort state is exposed with aria-sort on <th> (not on the sort button).
  • The table sets aria-busy while loading is true.
  • Prefer a visible caption or title near the table for screen reader context.

Released under the MIT License.