Skip to content

Commit f9b6a16

Browse files
feat (DataTable): add getRowId support to get unique row key (#690)
* feat: add getRowKey support to get unique row key * chore: rename prop to match tanstack API
1 parent c79eb7e commit f9b6a16

5 files changed

Lines changed: 32 additions & 1 deletion

File tree

apps/www/src/content/docs/components/datatable/index.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ function MyTable() {
156156

157157
Columns can be configured with various options:
158158

159+
**Performance:** Pass a stable `columns` reference (e.g. define at module scope or wrap in `useMemo`) so the table doesn't recompute filters, grouping, or sort state on every render.
160+
161+
**Row ids:** For sortable or filterable tables, pass `getRowId` so each row has a stable React key (e.g. `getRowId={(row) => row.id}` or `getRowId={(row) => row.uuid}`).
162+
159163
```ts
160164
interface DataTableColumnDef<TData, TValue> {
161165
accessorKey: string; // Key to access data

apps/www/src/content/docs/components/datatable/props.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ export interface DataTableProps {
3535
onColumnVisibilityChange?: (
3636
columnVisibility: Record<string, boolean>
3737
) => void;
38+
39+
/**
40+
* Return a stable unique id for each row (used as React key).
41+
* Use for sortable/filterable tables to avoid key issues when rows reorder.
42+
*/
43+
getRowId?: (row: any, index: number) => string;
3844
}
3945

4046
export interface DataTableQuery {

packages/raystack/components/data-table/__tests__/data-table.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,4 +575,21 @@ describe('DataTable', () => {
575575
expect(screen.queryByTestId('zero-state')).not.toBeInTheDocument();
576576
});
577577
});
578+
579+
describe('getRowId', () => {
580+
it('renders with getRowId callback for stable row keys', () => {
581+
render(
582+
<DataTable
583+
data={mockData}
584+
columns={mockColumns}
585+
defaultSort={{ name: 'name', order: 'asc' }}
586+
getRowId={row => row.id}
587+
>
588+
<DataTable.Content />
589+
</DataTable>
590+
);
591+
expect(screen.getByRole('table')).toBeInTheDocument();
592+
expect(screen.getByText('John Doe')).toBeInTheDocument();
593+
});
594+
});
578595
});

packages/raystack/components/data-table/data-table.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ function DataTableRoot<TData, TValue>({
4747
onTableQueryChange,
4848
onLoadMore,
4949
onRowClick,
50-
onColumnVisibilityChange
50+
onColumnVisibilityChange,
51+
getRowId
5152
}: React.PropsWithChildren<DataTableProps<TData, TValue>>) {
5253
const defaultTableQuery = useMemo(
5354
() => getDefaultTableQuery(defaultSort, query),
@@ -121,6 +122,7 @@ function DataTableRoot<TData, TValue>({
121122
const table = useReactTable({
122123
data: groupedData as unknown as TData[],
123124
columns: columnsWithFilters,
125+
getRowId,
124126
getCoreRowModel: getCoreRowModel(),
125127
getExpandedRowModel: getExpandedRowModel(),
126128
getSubRows: row => (row as unknown as GroupedData<TData>)?.subRows || [],

packages/raystack/components/data-table/data-table.types.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ export interface DataTableProps<TData, TValue> {
112112
onLoadMore?: () => Promise<void>;
113113
onRowClick?: (row: TData) => void;
114114
onColumnVisibilityChange?: (columnVisibility: VisibilityState) => void;
115+
/** Return a stable unique id for each row (used as React key). Use for sortable/filterable tables. */
116+
getRowId?: (row: TData, index: number) => string;
115117
}
116118

117119
export type DataTableContentClassNames = {

0 commit comments

Comments
 (0)