Skip to content

Commit dbeca84

Browse files
Updated DataTable for alternate key (#5907)
Co-authored-by: Marie Lucca <[email protected]> Co-authored-by: Marie Lucca <[email protected]>
1 parent d406a45 commit dbeca84

File tree

4 files changed

+67
-4
lines changed

4 files changed

+67
-4
lines changed

.changeset/shaky-hornets-train.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
feat(Datatable): add optional getRowId prop to support custom row identifiers

packages/react/src/DataTable/DataTable.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@ export type DataTableProps<Data extends UniqueRow> = {
5050
* currently sorted column
5151
*/
5252
initialSortDirection?: Exclude<SortDirection, 'NONE'>
53+
54+
/**
55+
* Provide a function to determine the unique identifier for each row.
56+
* This function allows you to customize the key used for the row.
57+
* By default, the table uses the `id` field from the data.
58+
* @param rowData The row data object for which the ID is being retrieved.
59+
* @returns The unique identifier for the row, which can be a string or number.
60+
*/
61+
getRowId?: (rowData: Data) => string | number
62+
}
63+
64+
function defaultGetRowId<D extends UniqueRow>(row: D) {
65+
return row.id
5366
}
5467

5568
function DataTable<Data extends UniqueRow>({
@@ -60,12 +73,14 @@ function DataTable<Data extends UniqueRow>({
6073
data,
6174
initialSortColumn,
6275
initialSortDirection,
76+
getRowId = defaultGetRowId,
6377
}: DataTableProps<Data>) {
6478
const {headers, rows, actions, gridTemplateColumns} = useTable({
6579
data,
6680
columns,
6781
initialSortColumn,
6882
initialSortDirection,
83+
getRowId,
6984
})
7085

7186
return (

packages/react/src/DataTable/__tests__/DataTable.test.tsx

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import userEvent from '@testing-library/user-event'
2-
import {render, screen, getByRole, queryByRole, queryAllByRole} from '@testing-library/react'
2+
import {render, screen, getByRole, queryByRole, queryAllByRole, renderHook} from '@testing-library/react'
33
import React from 'react'
44
import {DataTable, Table} from '../../DataTable'
55
import type {Column} from '../column'
66
import {createColumnHelper} from '../column'
7-
import {getGridTemplateFromColumns} from '../useTable'
7+
import {getGridTemplateFromColumns, useTable} from '../useTable'
88

99
describe('DataTable', () => {
1010
it('should render a semantic <table> through `data` and `columns`', () => {
@@ -1064,4 +1064,44 @@ describe('DataTable', () => {
10641064
})
10651065
})
10661066
})
1067+
1068+
it('overrides row.id with result of getRowId function', () => {
1069+
const data = [
1070+
{id: 1, name: 'Sabine', _uid: 'abc123'},
1071+
{id: 2, name: 'The Matador', _uid: 'abc12334'},
1072+
]
1073+
1074+
const getRowId = (row: {id: number; name: string; _uid: string}) => row._uid
1075+
1076+
const {result} = renderHook(() =>
1077+
useTable({
1078+
data,
1079+
columns: [],
1080+
getRowId,
1081+
}),
1082+
)
1083+
1084+
expect(result.current.rows[0].id).toBe('abc123')
1085+
expect(result.current.rows[1].id).toBe('abc12334')
1086+
})
1087+
1088+
it('uses default row.id when getRowId is not provided', () => {
1089+
const data = [
1090+
{id: 1, name: 'Sabine', _uid: 'abc123'},
1091+
{id: 2, name: 'The Matador', _uid: 'abc12334'},
1092+
]
1093+
1094+
const getRowId = (row: {id: number; name: string; _uid: string}) => row.id
1095+
1096+
const {result} = renderHook(() =>
1097+
useTable({
1098+
data,
1099+
columns: [],
1100+
getRowId,
1101+
}),
1102+
)
1103+
1104+
expect(result.current.rows[0].id).toBe('1')
1105+
expect(result.current.rows[1].id).toBe('2')
1106+
})
10671107
})

packages/react/src/DataTable/useTable.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface TableConfig<Data extends UniqueRow> {
99
data: Array<Data>
1010
initialSortColumn?: string | number
1111
initialSortDirection?: Exclude<SortDirection, 'NONE'>
12+
getRowId: (rowData: Data) => string | number
1213
}
1314

1415
interface Table<Data extends UniqueRow> {
@@ -47,6 +48,7 @@ export function useTable<Data extends UniqueRow>({
4748
data,
4849
initialSortColumn,
4950
initialSortDirection,
51+
getRowId,
5052
}: TableConfig<Data>): Table<Data> {
5153
const [rowOrder, setRowOrder] = useState(data)
5254
const [prevData, setPrevData] = useState(data)
@@ -181,15 +183,16 @@ export function useTable<Data extends UniqueRow>({
181183
return {
182184
headers,
183185
rows: rowOrder.map(row => {
186+
const rowId = getRowId(row)
184187
return {
185-
id: `${row.id}`,
188+
id: `${rowId}`,
186189
getValue() {
187190
return row
188191
},
189192
getCells() {
190193
return headers.map(header => {
191194
return {
192-
id: `${row.id}:${header.id}`,
195+
id: `${rowId}:${header.id}`,
193196
column: header.column,
194197
rowHeader: header.column.rowHeader ?? false,
195198
getValue() {

0 commit comments

Comments
 (0)