Skip to main content

Custom subcomponents

Every part of the grid is a slot. Two props drive them — the standard MUI pattern:

  • slotsreplace a part with your own component.
  • slotPropsinject props / sx / className into the built-in part.
<DataTable
columns={columns}
data={rows}
slots={{ noRowsOverlay: MyEmptyState }} // replace
slotProps={{ cell: { sx: { fontVariantNumeric: 'tabular-nums' } } }} // restyle
/>

Slots are a flat map of descriptive keys (not nested by section) — pass only what you override; each falls back to the built-in.

Replace vs. restyle — which to reach for

You want to…UseWhy
Recolour / space / align a partslotProps.<key>.sxMerges with built-in styling; you keep roles, refs, tokens.
Add a className or leaf propslotProps.<key>Spread onto the part (leaf controls take yours last, so overrides win).
Swap the markup entirelyslots.<key>Full control of the element.

Prefer slotProps first. A structural part (row, cell, header) never loses its required ARIA roles, refs, or keyboard wiring when you only inject sx/props — and the root's --dt-* design tokens are never clobbered. Reach for slots only when you truly need different markup.

Slot catalogue

The keys, grouped. The full table lives in the Props reference:

Structure

root · scroller · grid · header · headerRow · headerCell · body · row · cell · detailPanel · footer · pagination · loadingOverlay · noRowsOverlay

Toolbar & controls

toolbar · searchInput · columnFilterControl · columnVisibilityControl · densityControl · viewsControl · exportButton · refreshButton · resetButton · bulkActionsToolbar

Icons

searchIcon · clearIcon · filterIcon · addFilterIcon · columnsIcon · densityIcon · exportIcon · refreshIcon · resetIcon · sortIconAsc · sortIconDesc · expandIcon · collapseIcon — swap in any icon set (e.g. lucide). See Custom icons.

Auto-generated columns

The grid injects checkbox, expander, and row-actions columns when you enable those features. Configure them through slotProps with these three keys:

KeyConfigures
selectionColumnthe checkbox column (Selection)
expandColumnthe expander column (Row expansion)
actionsColumnthe auto row-actions column (getRowActions)
<DataTable
columns={columns}
data={rows}
enableRowSelection
enableColumnPinning
slotProps={{ selectionColumn: { enablePinning: true } }} // pin the checkboxes with the left band
/>

Merge semantics

Every slotProps entry's sx, className, and style merge with the built-in styling — yours wins per property, and nothing structural is lost. Leaf controls (pagination, toolbar buttons) spread your props last, so a deliberate override always wins:

slotProps={{ pagination: { rowsPerPageOptions: [10, 25, 100] } }}

Replace a whole region

For a bespoke toolbar or footer, replace the region and drive the grid through apiRef:

<DataTable
columns={columns}
data={rows}
slots={{ toolbar: MyToolbar }} // MyToolbar calls apiRef.current.filtering.setGlobalFilter(…), etc.
/>

To only rearrange the built-in toolbar controls (not replace them), use renderToolbar instead — it hands you each ready-made control element.