-
Notifications
You must be signed in to change notification settings - Fork 0
Slots API
📝 Generated from
docs/customization/slots-api.md. Edit it there; changes made in the wiki are overwritten.
The Slots API allows you to replace any built-in component in the DataGrid with your own custom implementation.
Every slot is typed React.ComponentType<Record<string, unknown>>, and every slotProps entry is Record<string, unknown>. A slot component therefore takes props: Record<string, unknown> and narrows the props it uses; the examples below cast to a type alias describing the props the grid passes. (A component declared with its own required props, such as (props: { page: number }) => …, is rejected by TypeScript.) The props from slotProps.<slot> are spread last, so they can override the grid's props.
Add a custom toolbar above the grid (commonly used for export buttons, filters, actions).
Props received:
{
apiRef: React.MutableRefObject<GridApi>;
columns: GridColDef[]; // every column in display order, hidden ones included
baseColumns: GridColDef[]; // the `columns` prop as passed
aggregationModel: GridAggregationModel;
onAggregationModelChange: (model: GridAggregationModel) => void;
pivotModel?: GridPivotModel; // only when pivotMode, pivotModel or onPivotModelChange is set
onPivotModelChange?: (model: GridPivotModel) => void;
filterModel: GridFilterModel;
onFilterModelChange: (model: GridFilterModel) => void;
columnVisibilityModel: GridColumnVisibilityModel;
onColumnVisibilityModelChange: (model: GridColumnVisibilityModel) => void;
onColumnReorder?: (fromField: string, toField: string) => void; // undefined with disableColumnReorder
onColumnOrderReset?: () => void; // undefined with disableColumnReorder
forceColumnsOpen: boolean; // the column menu's "Manage columns" asked for the Columns panel
onColumnsPanelClose: () => void;
// ...plus any props from slotProps.toolbar
}These match GridToolbarProps, so slots={{ toolbar: GridToolbar }} gives the built-in toolbar.
Example:
import { DataGrid, exportToCsv, exportToExcel, type GridApi, type GridColDef } from '@opencorestack/opengridx';
import type { MutableRefObject } from 'react';
type ToolbarSlotProps = { apiRef: MutableRefObject<GridApi>; columns: GridColDef[] };
function CustomToolbar(props: Record<string, unknown>) {
const { apiRef, columns } = props as ToolbarSlotProps;
const exportRows = () => apiRef.current.getAllFilteredRows();
return (
<div style={{ padding: '12px', display: 'flex', gap: '8px' }}>
<button type="button" onClick={() => exportToCsv(exportRows(), columns)}>
Export CSV
</button>
<button type="button" onClick={() => exportToExcel(exportRows(), columns)}>
Export Excel
</button>
</div>
);
}
<DataGrid rows={rows} columns={columns} slots={{ toolbar: CustomToolbar }} />toolbar accepts any React component type: function, class, React.memo, forwardRef or lazy. A plain function toolbar may be defined inline inside your own component: the grid keys it on its source code, so it keeps its state (open panels, typed search) when your component re-renders and remounts only when you pass a toolbar with different code. A class, memo or forwardRef toolbar is rendered as a normal element, so define it outside render to keep its identity stable.
Replace the default pagination component. It is rendered only while pagination is in effect (pagination set, no row grouping, paginationMode not "infinite"), is not rendered when a footer slot is set, and is used by list view too.
Props received:
{
page: number; // Current page (0-based), clamped to the last page client-side
pageSize: number; // Current page size
rowCount: number; // Rows being paged: filtered, unpinned rows; the server total in paginationMode="server"
pageSizeOptions: number[]; // Available page sizes (default [10, 25, 50, 100])
onPageChange: (page: number) => void;
onPageSizeChange: (size: number) => void; // also resets to page 0
localeText?: Pick<GridLocaleText, 'paginationRowsPerPage' | 'paginationOf' | 'paginationPage'>; // only when the localeText prop is set
// ...plus any props from slotProps.pagination
}Example:
<DataGrid
rows={rows}
columns={columns}
pagination
slots={{ pagination: CustomPagination }}
slotProps={{ pagination: { customProp: 'value' } }}
/>Replace the empty state shown when there are no rows.
Props received:
{
// Only the props from slotProps.noRowsOverlay
}Example:
function CustomNoRows() {
return (
<div style={{ padding: '40px', textAlign: 'center' }}>
<h3>No data available</h3>
<p>Try adjusting your filters</p>
</div>
);
}
<DataGrid
rows={rows}
columns={columns}
slots={{ noRowsOverlay: CustomNoRows }}
/>Replace the loading state overlay.
Props received:
{
// Only the props from slotProps.loadingOverlay
}Example:
function CustomLoader() {
return (
<div style={{ padding: '40px', textAlign: 'center' }}>
<Spin size="large" /> {/* Ant Design Spinner */}
<p>Loading data...</p>
</div>
);
}
<DataGrid
rows={rows}
columns={columns}
loading={isLoading}
slots={{ loadingOverlay: CustomLoader }}
/>Replace the entire footer section below the grid, including the default pagination. Rendered whenever the slot is set, including while row grouping is active, except in list view.
Props received (GridFooterSlotProps, v3.0+):
{
apiRef: React.MutableRefObject<GridApi>;
aggregationModel: GridAggregationModel;
aggregationResult: GridAggregationResult | null; // null when aggregationModel is empty, and in pivot mode
rowCount: number; // see below
pagination: boolean; // effective: false while row grouping is active or with paginationMode="infinite"
paginationModel: GridPaginationModel; // the model as held (not clamped to the last page)
pageSizeOptions: number[];
onPaginationModelChange: (model: GridPaginationModel) => void;
// ...plus any props from slotProps.footer
}rowCount is:
- with
paginationMode="server": the server total (thedataSourceresponse'srowCount, else therowCountprop, else the number of loaded rows); - otherwise, in a flat grid: the pager's
rowCount, the filtered rows without pinned rows (v3.0+; before, pinned rows were counted). WithfilterMode="server"it is every row the grid holds; withpaginationMode="infinite"the rows loaded so far; in pivot mode the pivot rows including the Grand Total row; - under row grouping and tree data: the data rows that pass the client filter (never group rows), whatever is expanded.
Example — a persistent grand-total bar that stays in sync with filtering:
import type { GridFooterSlotProps } from '@opencorestack/opengridx';
// Type the props you read; the grid checks them against GridFooterSlotProps.
function TotalsFooter({ aggregationResult, rowCount }: Pick<GridFooterSlotProps, 'aggregationResult' | 'rowCount'>) {
const total = aggregationResult?.amount;
return (
<div style={{ padding: '12px', borderTop: '1px solid #e0e0e0' }}>
{rowCount} rows · Total: {typeof total === 'number' ? total.toLocaleString() : '—'}
</div>
);
}
<DataGrid
rows={rows}
columns={columns}
aggregationModel={{ amount: 'sum' }}
slots={{ footer: TotalsFooter }}
/>
noRowsOverlay,loadingOverlayandfooterwere declared in the types before v2.1 but never rendered. They are wired from v2.1.
import { Select, Pagination, Spin, Empty } from 'antd';
import { DataGrid } from '@opencorestack/opengridx';
type PaginationSlotProps = {
page: number;
pageSize: number;
rowCount: number;
pageSizeOptions: number[];
onPageChange: (page: number) => void;
onPageSizeChange: (pageSize: number) => void;
};
function AntdPagination(props: Record<string, unknown>) {
const { page, pageSize, rowCount, pageSizeOptions, onPageChange, onPageSizeChange } =
props as PaginationSlotProps;
return (
<div style={{ display: 'flex', gap: '16px', padding: '12px 16px', justifyContent: 'flex-end' }}>
<Select
value={pageSize}
onChange={onPageSizeChange}
options={pageSizeOptions.map(s => ({ value: s, label: s }))}
/>
<Pagination
current={page + 1}
total={rowCount}
pageSize={pageSize}
onChange={(p) => onPageChange(p - 1)}
/>
</div>
);
}
function AntdNoRows() {
return <Empty description="No data available" />;
}
function AntdLoader() {
return (
<div style={{ padding: '40px', textAlign: 'center' }}>
<Spin size="large" />
</div>
);
}
function MyApp() {
return (
<DataGrid
rows={rows}
columns={columns}
pagination
loading={isLoading}
slots={{
pagination: AntdPagination,
noRowsOverlay: AntdNoRows,
loadingOverlay: AntdLoader
}}
slotProps={{
pagination: {
// Additional custom props if needed
}
}}
/>
);
}The library exports no props type for the pagination, overlay or footer slots (the toolbar's props are GridToolbarProps). Declare a type alias for the props you read and narrow Record<string, unknown> to it, as above. Use a type alias rather than an interface: an interface has no index signature, so props as MyInterface needs as unknown as.
type CustomPaginationProps = PaginationSlotProps & {
customProp?: string; // from slotProps.pagination
};
function CustomPagination(props: Record<string, unknown>) {
const { page, customProp } = props as CustomPaginationProps;
// Your implementation
}- Maintain Functionality: Ensure your custom component provides the same core functionality as the default.
- Accessibility: Include proper ARIA labels and keyboard navigation.
- Responsive Design: Make sure your component works on different screen sizes.
- Performance: Avoid expensive operations in render; use memoization where appropriate.
- Consistent Styling: Match your app's design system while maintaining usability.
- Custom Pagination Guide - Detailed examples with Ant Design and MUI
- DataGrid Props - Full TypeScript definitions
OpenGridX 3.2.2 · MIT · This wiki is generated from docs/ on every push to main. To fix a page, open a PR against the source file.
Start here
Components
- DataGrid
- Header
- Row
- Cell
- Toolbar
- Pagination
- Filter Panel
- Tooltip
- Column Visibility
- Column Grouping
- Column Resizing
- Empty State
- Error Overlay
- Aggregation Footer
Features
- Virtualization
- Filtering & Search
- Sorting & Pagination
- Custom Pagination
- Editing & Reordering
- Row Selection
- Clipboard
- Pinning
- State Persistence
- Aggregation & Pivot
- Tree Data & Grouping
- Cell Spanning
- Master-Detail
- Keyboard & Accessibility
- List View
- Infinite Scroll
- Data Source
- Loading States
- Toolbar Customization
- Export (CSV, Excel, JSON, Print)
- PDF Export
Customization
Upgrading
Contributing
- Contributing
- Testing
- Roadmap
- DataGrid orchestration
- GridRowMeta
- useGridControlledState
- useGridRowPipeline
- useGridColumns
- useGridVirtualization
- useGridVisibleRows
- useGridScrollSync
- useGridStateSnapshot