Headless UI for building powerful tables & datagrids for TS/JS
—
Row-level functionality including selection, expansion, grouping, pagination, and row pinning. These features provide comprehensive row management capabilities for interactive table experiences.
Multi-row and single-row selection with hierarchical selection support for nested data.
/** Row selection state mapping row IDs to selection status */
type RowSelectionState = Record<string, boolean>;
interface RowSelectionOptions<TData extends RowData> {
/** Row selection change handler */
onRowSelectionChange?: OnChangeFn<RowSelectionState>;
/** Enable row selection globally */
enableRowSelection?: boolean | ((row: Row<TData>) => boolean);
/** Enable multi-row selection */
enableMultiRowSelection?: boolean | ((row: Row<TData>) => boolean);
/** Enable sub-row selection */
enableSubRowSelection?: boolean | ((row: Row<TData>) => boolean);
/** Enable manual row selection mode */
manualRowSelection?: boolean;
/** Auto reset selection when data changes */
autoResetRowSelection?: boolean;
}
interface RowSelectionInstance<TData extends RowData> {
/** Get current row selection state */
getState(): { rowSelection: RowSelectionState };
/** Set row selection state */
setRowSelection(updater: Updater<RowSelectionState>): void;
/** Reset row selection to initial state */
resetRowSelection(defaultState?: boolean): void;
/** Get whether all rows are selected */
getIsAllRowsSelected(): boolean;
/** Get whether some rows are selected */
getIsSomeRowsSelected(): boolean;
/** Get whether all page rows are selected */
getIsAllPageRowsSelected(): boolean;
/** Get whether some page rows are selected */
getIsSomePageRowsSelected(): boolean;
/** Toggle all rows selection */
toggleAllRowsSelected(value?: boolean): void;
/** Toggle all page rows selection */
toggleAllPageRowsSelected(value?: boolean): void;
/** Get selected row model */
getSelectedRowModel(): RowModel<TData>;
/** Get filtered selected row model */
getFilteredSelectedRowModel(): RowModel<TData>;
/** Get grouped selected row model */
getGroupedSelectedRowModel(): RowModel<TData>;
}Usage Examples:
import { createTable } from "@tanstack/table-core";
// Basic row selection
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const table = createTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
onRowSelectionChange: setRowSelection,
state: {
rowSelection,
},
enableRowSelection: true,
enableMultiRowSelection: true,
});
// Conditional row selection
const table = createTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
enableRowSelection: (row) => row.original.status !== 'disabled',
enableMultiRowSelection: true,
});
// Selection management
const selectedRows = table.getSelectedRowModel().rows;
const isAllSelected = table.getIsAllRowsSelected();
table.toggleAllRowsSelected();
// Individual row selection
const firstRow = table.getRowModel().rows[0];
firstRow.toggleSelected();
const isSelected = firstRow.getIsSelected();Methods available on individual rows for selection management.
interface RowSelectionRow {
/** Get whether this row is selected */
getIsSelected(): boolean;
/** Get whether this row can be selected */
getCanSelect(): boolean;
/** Get whether this row can multi-select */
getCanMultiSelect(): boolean;
/** Get whether this row can select sub-rows */
getCanSelectSubRows(): boolean;
/** Toggle selection of this row */
toggleSelected(value?: boolean): void;
/** Get selection percentage for partially selected groups */
getIsAllSubRowsSelected(): boolean;
/** Get whether some sub-rows are selected */
getIsSomeSelected(): boolean;
}Utility functions for managing row selection state and logic.
/**
* Utility function for selecting rows
* @param rows - Array of rows to process
* @param rowSelection - Current selection state
* @returns Updated selection state
*/
function selectRowsFn<TData extends RowData>(
rows: Row<TData>[],
rowSelection: RowSelectionState
): RowSelectionState;
/**
* Check if a row is selected
* @param row - Row to check
* @param selection - Selection state
* @returns Whether row is selected
*/
function isRowSelected<TData extends RowData>(
row: Row<TData>,
selection: RowSelectionState
): boolean;
/**
* Check if a sub-row is selected
* @param row - Parent row to check
* @param selection - Selection state
* @returns Whether sub-row is selected
*/
function isSubRowSelected<TData extends RowData>(
row: Row<TData>,
selection: RowSelectionState
): boolean;Expand and collapse rows with hierarchical data support and custom expansion logic.
/** Expanded state mapping row IDs to expansion status */
type ExpandedState = Record<string, boolean>;
/** Alternative expanded state as array of row IDs */
type ExpandedStateList = string[];
interface ExpandedOptions<TData extends RowData> {
/** Expanded state change handler */
onExpandedChange?: OnChangeFn<ExpandedState>;
/** Auto reset expanded state when data changes */
autoResetExpanded?: boolean;
/** Enable expanding rows */
enableExpanding?: boolean;
/** Get sub-rows for a given row */
getSubRows?: (originalRow: TData, index: number) => TData[] | undefined;
/** Get whether a row can expand */
getCanExpand?: (row: Row<TData>) => boolean;
/** Get expanded row model */
getExpandedRowModel?: () => RowModel<TData>;
/** Get whether row is expanded by default */
getIsRowExpanded?: (row: Row<TData>) => boolean;
/** Manual expanding mode */
manualExpanding?: boolean;
/** Maximum expansion depth */
maxLeafRowFilterDepth?: number;
/** Filter from leafs up */
filterFromLeafRows?: boolean;
}
interface ExpandedInstance<TData extends RowData> {
/** Get current expanded state */
getState(): { expanded: ExpandedState };
/** Set expanded state */
setExpanded(updater: Updater<ExpandedState>): void;
/** Reset expanded state */
resetExpanded(defaultState?: boolean): void;
/** Get whether all rows are expanded */
getIsAllRowsExpanded(): boolean;
/** Get whether some rows are expanded */
getIsSomeRowsExpanded(): boolean;
/** Toggle all rows expansion */
toggleAllRowsExpanded(expanded?: boolean): void;
/** Get pre-expanded row model */
getPreExpandedRowModel(): RowModel<TData>;
/** Get expanded row model */
getExpandedRowModel(): RowModel<TData>;
}Usage Examples:
// Row expanding setup
const [expanded, setExpanded] = useState<ExpandedState>({});
const table = createTable({
data: hierarchicalData,
columns,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
onExpandedChange: setExpanded,
state: {
expanded,
},
getSubRows: (originalRow) => originalRow.subRows,
});
// Expand/collapse rows
const row = table.getRowModel().rows[0];
row.toggleExpanded();
const isExpanded = row.getIsExpanded();
const canExpand = row.getCanExpand();
// Expand all rows
table.toggleAllRowsExpanded(true);Methods available on individual rows for expansion management.
interface ExpandedRow {
/** Get whether this row is expanded */
getIsExpanded(): boolean;
/** Get whether this row can expand */
getCanExpand(): boolean;
/** Toggle expansion of this row */
toggleExpanded(expanded?: boolean): void;
/** Get toggle handler for this row */
getToggleExpandedHandler(): () => void;
}Group rows by column values with aggregation support and nested grouping.
/** Grouping state as array of column IDs to group by */
type GroupingState = string[];
/** Grouping column mode */
type GroupingColumnMode = false | 'reorder' | 'remove';
interface GroupingOptions {
/** Grouping state change handler */
onGroupingChange?: OnChangeFn<GroupingState>;
/** Auto reset grouping when data changes */
autoResetGrouping?: boolean;
/** Enable grouping globally */
enableGrouping?: boolean;
/** Get grouped row model */
getGroupedRowModel?: () => RowModel<TData>;
/** Manual grouping mode */
manualGrouping?: boolean;
/** Group expanded state */
groupedColumnMode?: GroupingColumnMode;
}
interface GroupingInstance<TData extends RowData> {
/** Get current grouping state */
getState(): { grouping: GroupingState };
/** Set grouping state */
setGrouping(updater: Updater<GroupingState>): void;
/** Reset grouping state */
resetGrouping(defaultState?: boolean): void;
/** Get pre-grouped row model */
getPreGroupedRowModel(): RowModel<TData>;
/** Get grouped row model */
getGroupedRowModel(): RowModel<TData>;
}Usage Examples:
import { getGroupedRowModel } from "@tanstack/table-core";
// Row grouping setup
const [grouping, setGrouping] = useState<GroupingState>([]);
const table = createTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getGroupedRowModel: getGroupedRowModel(),
onGroupingChange: setGrouping,
state: {
grouping,
},
enableGrouping: true,
});
// Group by columns
table.setGrouping(['department', 'role']);
// Column-level grouping methods
const deptColumn = table.getColumn('department');
deptColumn.toggleGrouping();
const groupingIndex = deptColumn.getGroupedIndex();Paginate large datasets with customizable page sizes and navigation.
/** Pagination state */
interface PaginationState {
pageIndex: number;
pageSize: number;
}
interface PaginationOptions {
/** Pagination state change handler */
onPaginationChange?: OnChangeFn<PaginationState>;
/** Auto reset pagination when data changes */
autoResetPageIndex?: boolean;
/** Enable manual pagination mode */
manualPagination?: boolean;
/** Get paginated row model */
getPaginationRowModel?: () => RowModel<TData>;
/** Total row count for manual pagination */
rowCount?: number;
/** Page count for manual pagination */
pageCount?: number;
}
interface PaginationInstance<TData extends RowData> {
/** Get current pagination state */
getState(): { pagination: PaginationState };
/** Set pagination state */
setPagination(updater: Updater<PaginationState>): void;
/** Reset pagination state */
resetPagination(defaultState?: boolean): void;
/** Set page index */
setPageIndex(updater: Updater<number>): void;
/** Reset page index */
resetPageIndex(defaultState?: boolean): void;
/** Set page size */
setPageSize(updater: Updater<number>): void;
/** Reset page size */
resetPageSize(defaultState?: boolean): void;
/** Get page count */
getPageCount(): number;
/** Get row count */
getRowCount(): number;
/** Get pre-paginated row model */
getPrePaginationRowModel(): RowModel<TData>;
/** Get paginated row model */
getPaginationRowModel(): RowModel<TData>;
/** Get current page */
getPage(): Row<TData>[];
/** Get whether can go to previous page */
getCanPreviousPage(): boolean;
/** Get whether can go to next page */
getCanNextPage(): boolean;
/** Go to previous page */
previousPage(): void;
/** Go to next page */
nextPage(): void;
/** Get first page */
firstPage(): void;
/** Get last page */
lastPage(): void;
/** Get page options */
getPageOptions(): number[];
}Usage Examples:
import { getPaginationRowModel } from "@tanstack/table-core";
// Pagination setup
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const table = createTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onPaginationChange: setPagination,
state: {
pagination,
},
});
// Pagination controls
const canPrevious = table.getCanPreviousPage();
const canNext = table.getCanNextPage();
const pageCount = table.getPageCount();
const currentPage = table.getState().pagination.pageIndex + 1;
// Navigation
table.previousPage();
table.nextPage();
table.setPageIndex(0);
table.setPageSize(25);Pin specific rows to the top or bottom of the table.
/** Row pinning position */
type RowPinningPosition = 'top' | 'bottom' | false;
/** Row pinning state */
interface RowPinningState {
top?: string[];
bottom?: string[];
}
interface RowPinningOptions<TData extends RowData> {
/** Row pinning change handler */
onRowPinningChange?: OnChangeFn<RowPinningState>;
/** Enable row pinning globally */
enableRowPinning?: boolean | ((row: Row<TData>) => boolean);
/** Keep pinned rows */
keepPinnedRows?: boolean;
/** Auto reset row pinning when data changes */
autoResetRowPinning?: boolean;
}
interface RowPinningInstance<TData extends RowData> {
/** Get current row pinning state */
getState(): { rowPinning: RowPinningState };
/** Set row pinning state */
setRowPinning(updater: Updater<RowPinningState>): void;
/** Reset row pinning state */
resetRowPinning(defaultState?: boolean): void;
/** Get whether any rows are pinned */
getIsSomeRowsPinned(position?: RowPinningPosition): boolean;
/** Get top pinned rows */
getTopRows(): Row<TData>[];
/** Get bottom pinned rows */
getBottomRows(): Row<TData>[];
/** Get center (unpinned) rows */
getCenterRows(): Row<TData>[];
}Usage Examples:
// Row pinning setup
const [rowPinning, setRowPinning] = useState<RowPinningState>({
top: [],
bottom: [],
});
const table = createTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
onRowPinningChange: setRowPinning,
state: {
rowPinning,
},
enableRowPinning: true,
});
// Pin/unpin rows
const row = table.getRowModel().rows[0];
row.pin('top');
row.pin('bottom');
row.pin(false); // Unpin
// Get pinned rows
const topRows = table.getTopRows();
const centerRows = table.getCenterRows();
const bottomRows = table.getBottomRows();Methods available on individual rows for pinning management.
interface RowPinningRow {
/** Get current pin position of this row */
getIsPinned(): RowPinningPosition;
/** Get pin index of this row */
getPinnedIndex(): number;
/** Get whether this row can be pinned */
getCanPin(): boolean;
/** Pin this row to specified position */
pin(position: RowPinningPosition): void;
}Row extensions for each feature providing additional methods and properties.
interface VisibilityRow<TData extends RowData> {
/** Get visible cells for this row */
getVisibleCells(): Cell<TData, unknown>[];
}
interface ColumnPinningRow<TData extends RowData> {
/** Get left pinned cells */
getLeftVisibleCells(): Cell<TData, unknown>[];
/** Get center cells */
getCenterVisibleCells(): Cell<TData, unknown>[];
/** Get right pinned cells */
getRightVisibleCells(): Cell<TData, unknown>[];
}
interface ColumnFiltersRow<TData extends RowData> {
/** Column filters don't add row methods */
}
interface GroupingRow {
/** Get grouping value for this row */
getGroupingValue(columnId: string): unknown;
/** Get whether this is a grouped row */
getIsGrouped(): boolean;
/** Get group level */
groupingColumnId?: string;
/** Get group value */
groupingValue?: unknown;
}Usage Examples:
// Working with row extensions
const row = table.getRowModel().rows[0];
// Visibility
const visibleCells = row.getVisibleCells();
// Pinning
const leftCells = row.getLeftVisibleCells();
const centerCells = row.getCenterVisibleCells();
const rightCells = row.getRightVisibleCells();
// Selection
const isSelected = row.getIsSelected();
row.toggleSelected();
// Expansion
const isExpanded = row.getIsExpanded();
row.toggleExpanded();
// Grouping
if (row.getIsGrouped()) {
console.log('Group value:', row.groupingValue);
console.log('Group column:', row.groupingColumnId);
}
// Pinning
const pinPosition = row.getIsPinned();
if (pinPosition) {
console.log(`Row is pinned to ${pinPosition}`);
}Install with Tessl CLI
npx tessl i tessl/npm-tanstack--table-core