Data Table

Primitive / Organismbeta

Data Table

Feature-rich table wrapper with search, sorting, pagination, selection, and column controls.

@glinui/uiComponent: data-table

Installation$

Install from the package for shared ownership, or from the registry when you want copy-paste control.

Package Manager$

pnpm add @glinui/ui @glinui/tokens

Registry$

pnpm dlx @glinui/cli@latest add data-table

Usage$

DataTable builds on the base Table primitive and adds first-party behaviors: search, sorting, selection, pagination, and column visibility.

Rows
NorthwindQualifiedMaya$42,000
Stellar ForgeProposalIlya$18,500
Blue HarborWonRae$63,200

Showing 1-3 of 6

Page 1 of 2

TSX
1import { Badge, DataTable } from "@glinui/ui"
2
3const columns = [
4{ id: "account", header: "Account", accessor: "account", sortable: true },
5{
6 id: "stage",
7 header: "Stage",
8 accessor: "stage",
9 sortable: true,
10 cell: ({ value }) => (
11 <Badge variant={value === "Won" ? "glass" : value === "Qualified" ? "outline" : "ghost"}>
12 {String(value)}
13 </Badge>
14 )
15},
16{ id: "owner", header: "Owner", accessor: "owner", sortable: true },
17{ id: "arr", header: "ARR", accessor: "arr", sortable: true, align: "right" }
18]
19
20const rows = [
21{ id: "op-4012", account: "Northwind", stage: "Qualified", owner: "Maya", arr: "$42,000" },
22{ id: "op-4015", account: "Stellar Forge", stage: "Proposal", owner: "Ilya", arr: "$18,500" },
23{ id: "op-4018", account: "Blue Harbor", stage: "Won", owner: "Rae", arr: "$63,200" },
24{ id: "op-4021", account: "Arcadia Labs", stage: "Discovery", owner: "Nico", arr: "$11,900" }
25]
26
27export function DataTableBasicDemo() {
28return (
29 <DataTable
30 columns={columns}
31 data={rows}
32 selectable
33 variant="glass"
34 striped
35 grid
36 pageSize={3}
37 getRowId={(row) => row.id}
38 />
39)
40}

Examples$

Compact Board With Sticky Header$

Rows
NorthwindQualifiedMaya$42,000
Stellar ForgeProposalIlya$18,500
Blue HarborWonRae$63,200
Arcadia LabsDiscoveryNico$11,900
HalcyonQualifiedLeah$27,600

Showing 1-5 of 6

Page 1 of 2

TSX
1import { DataTable } from "@glinui/ui"
2
3export function DataTableCompactDemo() {
4return (
5 <DataTable
6 columns={[
7 { id: "account", header: "Account", accessor: "account", sortable: true },
8 { id: "stage", header: "Stage", accessor: "stage", sortable: true },
9 { id: "owner", header: "Owner", accessor: "owner", sortable: true },
10 { id: "arr", header: "ARR", accessor: "arr", sortable: true, align: "right" },
11 ]}
12 data={[
13 { id: "op-4012", account: "Northwind", stage: "Qualified", owner: "Maya", arr: "$42,000" },
14 { id: "op-4015", account: "Stellar Forge", stage: "Proposal", owner: "Ilya", arr: "$18,500" },
15 { id: "op-4018", account: "Blue Harbor", stage: "Won", owner: "Rae", arr: "$63,200" },
16 { id: "op-4021", account: "Arcadia Labs", stage: "Discovery", owner: "Nico", arr: "$11,900" },
17 { id: "op-4022", account: "Halcyon", stage: "Qualified", owner: "Leah", arr: "$27,600" },
18 ]}
19 getRowId={(row) => row.id}
20 variant="matte"
21 size="sm"
22 stickyHeader
23 containerClassName="max-h-72"
24 pageSize={5}
25 searchable
26 />
27)
28}

Selection + Column Controls$

Enable selectable and hide low-priority columns with hidden/canHide to keep dense dashboards readable.

Rows
NorthwindQualified$42,000
Stellar ForgeProposal$18,500
Blue HarborWon$63,200
Arcadia LabsDiscovery$11,900

Showing 1-4 of 4

Page 1 of 1

TSX
1import { DataTable } from "@glinui/ui"
2
3export function DataTableSelectionDemo() {
4return (
5 <DataTable
6 columns={[
7 { id: "account", header: "Account", accessor: "account", sortable: true },
8 { id: "stage", header: "Stage", accessor: "stage", sortable: true },
9 { id: "owner", header: "Owner", accessor: "owner", sortable: true, hidden: true, canHide: true },
10 { id: "arr", header: "ARR", accessor: "arr", sortable: true, align: "right" },
11 ]}
12 data={[
13 { id: "op-4012", account: "Northwind", stage: "Qualified", owner: "Maya", arr: "$42,000" },
14 { id: "op-4015", account: "Stellar Forge", stage: "Proposal", owner: "Ilya", arr: "$18,500" },
15 { id: "op-4018", account: "Blue Harbor", stage: "Won", owner: "Rae", arr: "$63,200" },
16 { id: "op-4021", account: "Arcadia Labs", stage: "Discovery", owner: "Nico", arr: "$11,900" },
17 ]}
18 selectable
19 variant="outline"
20 pageSize={4}
21 />
22)
23}

Server Data Pattern$

For large datasets, fetch and paginate on the server, then pass only the current page to DataTable.

Use this pattern when your API owns filtering, sorting, and pagination.

TSX
1"use client"
2
3import * as React from "react"
4import { DataTable } from "@glinui/ui"
5
6const columns = [
7{ id: "account", header: "Account", accessor: "account", sortable: true },
8{ id: "stage", header: "Stage", accessor: "stage", sortable: true },
9{ id: "arr", header: "ARR", accessor: "arr", sortable: true, align: "right" }
10]
11
12export function DataTableServerPattern() {
13const [rows, setRows] = React.useState([])
14const [query, setQuery] = React.useState("")
15const [page, setPage] = React.useState(1)
16
17React.useEffect(() => {
18 const params = new URLSearchParams({ q: query, page: String(page) })
19 fetch(`/api/pipeline?${params.toString()}`)
20 .then((res) => res.json())
21 .then((payload) => setRows(payload.items))
22}, [query, page])
23
24return (
25 <DataTable
26 columns={columns}
27 data={rows}
28 searchable={false}
29 pageSize={20}
30 variant="glass"
31 emptyMessage="No matching records."
32 />
33)
34}

Accessibility$

  • Built on semantic table elements (table, thead, tbody, th, and td) for screen-reader compatibility.
  • Search input, page-size select, and selection checkboxes ship with labels by default.
  • Sort actions are focusable controls in headers and work with keyboard activation (Enter / Space).
  • Keep column names concise and unique so assistive tech announces context clearly.

Reduced Motion$

DataTable inherits reduced-motion behavior from Table, Input, Select, and Button. Hover/focus transitions are non-essential and respect user preference settings.

API Reference$

PropTypeRequiredDefaultDescription
classNamestringNo-Auto-generated from TypeScript source.
columnsDataTableColumn<TData>[]Yes-Auto-generated from TypeScript source.
dataTData[]Yes-Auto-generated from TypeScript source.
emptyMessagestringNo"No results."Auto-generated from TypeScript source.
getRowId(row: TData, index: number) => stringNo-Auto-generated from TypeScript source.
onRowClick(row: TData) => voidNo-Auto-generated from TypeScript source.
onSelectionChange(rows: TData[]) => voidNo-Auto-generated from TypeScript source.
pageSizenumberNo10Auto-generated from TypeScript source.
pageSizeOptionsnumber[]No[10, 20, 50]Auto-generated from TypeScript source.
rowTone(row: TData) => TableRowToneNo-Auto-generated from TypeScript source.
searchablebooleanNotrueAuto-generated from TypeScript source.
searchPlaceholderstringNo"Search rows..."Auto-generated from TypeScript source.
selectablebooleanNofalseAuto-generated from TypeScript source.

Source$

TSX
1import { DataTable } from "@glinui/ui"
packages/ui/src/components/data-table.tsx
packages/ui/src/components/table.tsx
packages/ui/src/tests/data-table.test.tsx

Generated API Snapshot

Beta

Auto-extracted from TypeScript source in packages/ui/src/components/data-table.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.

Generated: 2026-02-19T17:59:28.468Z · Full index: /docs/api-metadata

Primary Props Type

DataTableProps

DataTableProps

PropTypeRequiredDefaultDescription
classNamestringNo--
columnsDataTableColumn<TData>[]Yes--
dataTData[]Yes--
emptyMessagestringNo"No results."-
getRowId(row: TData, index: number) => stringNo--
onRowClick(row: TData) => voidNo--
onSelectionChange(rows: TData[]) => voidNo--
pageSizenumberNo10-
pageSizeOptionsnumber[]No[10, 20, 50]-
rowTone(row: TData) => TableRowToneNo--
searchablebooleanNotrue-
searchPlaceholderstringNo"Search rows..."-
selectablebooleanNofalse-