Skip to main content

<DataTable> props

Every prop, grouped by area. Use the search (top right) to find a setting fast.

How to read these tables — the Type column doubles as the list of possible values (e.g. a union like 'client' | 'server' is the allowed set); Default is what you get when you omit the prop; the Description says what it does and when to reach for it. Naming follows a few conventions:

PatternMeaningExample
enableXFeature toggle (boolean)enableSorting, enablePagination
xModeClient-side vs server-sidefilterMode, paginationMode
onXChangeState-change callback — see EventsonSortingChange
renderXCustom render functionrenderDetailPanel, renderBulkActions
adjectiveVisual modifierstriped, hover, fitToScreen

T is your row type — pass it as <DataTable<User> …> for typed columns, callbacks, and apiRef. Only the most-used props are listed here; deprecated v1 aliases and niche export/logging options live in the TypeScript types. Feature deep-dives are linked from each section.

Data​

PropTypeDefaultDescription
columnsColumnDef<T>[]—TanStack column definitions (+ align, type, wrapText, disableRowClick, export options).
dataT[][]Row data (client mode).
rowCountnumber—Total row count (server mode).
getRowId(row, index) => string—Stable row id; defaults to row[idKey].
idKeykeyof T'id'Shorthand row-id field.
dataMode'client' | 'server''client'Client-held or server-fetched.
onFetchData(filters, meta) => Promise<{ data, total }>—Server fetch handler.
initialStatePartial<TableState>—Initial sorting/pagination/pinning/visibility/sizing/density.
stateKeystring—Persist view state under this key (see State persistence).
persistPersistOptions—Tune persistence: storage ('local'/'session'/custom), include, debounceMs.
onDataStateChange(state) => void—Any table-state change.

Sorting / Filtering / Pagination​

See Sorting · Filtering · Quick Filter · Pagination.

PropTypeDefaultDescription
enableSortingbooleantrueClick headers to sort. Turn off for a fixed-order grid.
sortingMode'client' | 'server''client''client' sorts in memory; 'server' hands the sort model to onFetchData — use for datasets you don't hold locally.
onSortingChange(sorting) => void—Observe the sort model (sync a URL, analytics).
enableGlobalFilterbooleantrueCollapsible toolbar quick-search across all columns.
enableColumnFilterbooleanfalsePer-column rule builder (field · operator · value) with an active-count badge.
filterMode'client' | 'server''client'Where matching happens (shared by global + column filters). 'server' → filter via onFetchData.
enablePaginationbooleanfalseShow the footer pager. Off = render every row (pair with virtualization for big data).
paginationMode'client' | 'server''client''server' requests one page at a time via onFetchData — needs rowCount.
rowsPerPageOptionsnumber[][5,10,25,50,100]Page-size choices; [] hides the selector.

Selection​

See Selection.

PropTypeDefaultDescription
enableRowSelectionboolean | (row) => booleanfalseAdd the checkbox column. Pass a predicate to allow selection only on some rows.
enableMultiRowSelectionbooleantruefalse = single-select (radio-like) — use for "pick one".
selectMode'page' | 'all''page'Whether "select all" spans the current page or the whole (filtered) dataset.
isRowSelectable({ row, id }) => boolean—Disable specific rows' checkboxes (e.g. locked records).
enableBulkActionsbooleanfalseShow the contextual bar (count + Clear) when rows are selected.
renderBulkActions(selection) => ReactNode—Your actions for the bulk bar (Delete, Assign…). selection carries include/exclude ids.
enableClipboardCopybooleanfalseAdd a Copy action to the bulk bar (TSV to clipboard).
onSelectionChange(selection) => void—React to selection (enable a button, show a banner).

Columns​

See Columns · Column pinning · Cells.

PropTypeDefaultDescription
enableColumnResizingbooleanfalseDrag a header edge to resize; persists with stateKey.
columnResizeMode'onChange' | 'onEnd''onChange''onChange' resizes live as you drag; 'onEnd' waits for release (steadier for very wide grids).
enableColumnReorderingbooleanfalseDrag headers to reorder (also exposed in the columns panel).
enableColumnPinningbooleanfalseFreeze columns left/right; seed with initialState.columnPinning.
enableColumnVisibilitybooleantrueShow/hide checkboxes in the toolbar columns panel.
enableColumnMenubooleantruePer-column header ⋮ menu (sort, hide, autosize). Opt one column out with columnDef.disableColumnMenu.
onColumnOrderChange / onColumnPinningChange / onColumnVisibilityChange / onColumnSizingChange(state) => void—Observe each column-layout change — see Events.

Appearance & layout​

PropTypeDefaultDescription
density'compact' | 'standard' | 'comfortable'—Controlled density — overrides the selector.
defaultDensity'compact' | 'standard' | 'comfortable''standard'Uncontrolled initial density; the selector can still change it.
stripedbooleanfalseAlternate row background.
hoverbooleantrueHighlight the hovered row.
fitToScreenbooleantrueStretch columns to fill width.
stickyHeaderboolean—Pin the header; on its own it bounds the body at maxHeight (see Height & scrolling).
stickyFooterboolean—Pin the pagination footer; like stickyHeader, it bounds the body.
maxHeightstring | number480¹Cap the scroll viewport; active on its own. ¹Default applied only in a bounded mode.
heightstring | number—Fix the grid height ('100%' fills a sized parent); the body scrolls to fill.
minHeightstring | number—Optional floor so a near-empty grid doesn't collapse.
enableVirtualizationbooleanfalseRender only visible rows.
estimatedRowHeightnumber52Virtualizer row-height estimate.
getRowClassName({ row, index }) => string—Conditional row class.
getCellClassName({ row, columnId, value }) => string—Conditional cell class.

Toolbar​

PropTypeDefaultDescription
toolbarVariant'icon' | 'text''icon'Icon-only (tooltip) or icon + label buttons (guide).
enableDensitySelectorbooleanfalseDensity menu.
enableExportbooleanfalseExport menu.
enableResetbooleanfalse"Reset layout" button — restores the column layout only (no data reload).
resetActionsResetLayoutAction[]['columnOrder','columnPinning','columnSizing']What Reset restores. Add 'columnVisibility', 'rowPinning', 'filters', 'sorting', 'pagination'.
enableRefreshbooleanfalse"Refresh data" button — re-fetches data (onFetchData in server mode).
enableListViewbooleanfalseGrid ⇄ list view toggle.
listView / onListViewChangeboolean / (next) => void—Controlled list-view mode.
renderListItem(params) => ReactNode—Render a row as a full-width list item.
rowHeightnumber—Fixed row height in px (overrides density).
extraFilterReactNode—Custom toolbar content (right side by default).
footerFilterReactNode—Custom content on the left of the footer, opposite pagination (e.g. a "show deleted" toggle). The footer appears whenever this or enablePagination is set; below the sm breakpoint the pager wraps onto its own line beneath it.
renderToolbar(controls) => ReactNode—Rearrange the built-in toolbar controls (guide).

States & customization​

PropTypeDefaultDescription
loadingbooleanfalseShow skeleton rows.
noRowsMessagestring | ReactNode'No rows'Empty-state message.
skeletonRowsnumber5Skeleton row count.
slotsPartial<DataTableSlots>—Replace any sub-component.
slotPropsPartialSlotProps—Inject props/sx into parts.
apiRefRefObject<DataTableApi<T>>—Imperative handle.
sxSxProps—Root styles.
onRowClick(event, row) => void—Fires when a row is clicked. Not fired from the selection, expander, or actions cells, an editable cell, or any column with disableRowClick.
selectOnRowClickbooleanfalseClicking anywhere in a row toggles its selection (needs enableRowSelection; respects single/multi mode + per-row selectability). Composes with onRowClick.
loggingboolean | DataTableLoggingOptionsfalseDebug logging.

Slots & slotProps​

slots replaces a part; slotProps injects props/sx into one — the MUI pattern. Slots are a flat map of descriptive keys (not nested by section); pass only what you want to override, and each falls back to the built-in.

Structure slots​

SlotPart
root, scroller, gridouter card / scroll area / grid
header, headerRow, headerCellheader parts
body, row, cell, detailPanelbody parts
footer, paginationfooter / pagination
loadingOverlay, noRowsOverlayoverlays

Toolbar & control slots​

SlotPart
toolbarthe whole toolbar
searchInputglobal search field
columnFilterControl, columnVisibilityControl, densityControltoolbar menus
viewsControlsaved-views control
exportButton, refreshButton, resetButtontoolbar buttons
bulkActionsToolbarselection bulk-actions bar

Each control is both swappable (slots.<key>) and injectable (slotProps.<key>) — pass a component to replace it, or props/sx to style the built-in one.

Icon slots​

Swap in your own set (e.g. lucide); defaults are built-in line icons. See Custom icons.

SlotUsed for
searchIcon, clearIconsearch / clear
filterIcon, addFilterIconcolumn filter
columnsIconcolumns panel (show/hide, pin, reorder)
densityIcon, exportIcon, refreshIcon, resetIcontoolbar buttons
sortIconAsc, sortIconDescheader sort
expandIcon, collapseIconrow expand / collapse

slotProps accepts the same keys, plus selectionColumn / expandColumn / actionsColumn to configure the auto-generated checkbox / expander / row-actions columns — e.g. slotProps={{ selectionColumn: { enablePinning: true } }}.

Every slotProps entry's sx, className, and style merge with the built-in styling (yours wins per-property) — a structural part never loses its required roles, refs, or keyboard wiring, and the root's design tokens are never clobbered. Leaf controls (pagination, toolbar buttons) spread your props last, so a deliberate override wins.

slotProps.toolbar forwards only DOM-safe extras onto the toolbar container: data-*, aria-*, id, role, title, tabIndex, and on* handlers. Config-style keys such as refreshButtonProps: {…} or showRefresh: true are dropped, so they don't end up as attributes on the <div>. Target a single control through its own key instead, e.g. slotProps.refreshButton.

Height & scrolling​

The grid is a flex column — header pinned to the top, footer to the bottom, body scrolling between. Three height modes: auto (default, grows to content), maxHeight (caps and scrolls), and height (fixed, or "100%" to fill a sized parent). A bounded height is all the body needs to scroll — minHeight is not required.

See Height & scrolling for the full guide with a live demo of each mode.

State persistence​

Give the grid a stable stateKey and it remembers its view state — pagination, sort, global search, column filters, column order / width / visibility / pinning, and density — across reloads and remounts, with no save/restore wiring:

<DataTable columns={columns} data={rows} stateKey="expenses" enablePagination enableColumnPinning />

Try it — sort, paginate, reorder/resize/hide a column, then reload the page: the view comes back.

Loading demo…

It reads the saved snapshot into initialState on mount and writes (debounced) on change. Selection and row expansion are excluded by default. Tune it with persist:

<DataTable
stateKey="expenses"
persist={{
storage: 'session', // 'local' (default) | 'session' | a custom Storage-like object
include: ['sorting', 'pagination', 'columnPinning'], // whitelist (default: all but selection/expansion)
debounceMs: 500, // write throttle (default 300)
}}
/>

SSR-safe (no-ops without window; a custom storage object is honored anywhere). Storage keys are namespaced as dt:<stateKey>. To forget a saved view (e.g. a "Reset" button), call clearPersistedState(stateKey, persist?) and remount/reload.

Dark mode & cssVariables themes​

The grid derives every colour from your MUI theme, so it follows light/dark automatically — including the modern setup createTheme({ cssVariables: true, colorSchemes: { light, dark } }): it reads palette values via theme.vars and emits its mode-dependent defaults with applyStyles('dark'). To customise grid colours per scheme, use createDataTableTheme (palette + optional darkPalette), which emits colorSchemes overrides that compose cleanly with a cssVariables app theme.