ra-datagrid-ag
This package contains the <DatagridAG>
component, an alternative datagrid with advanced features, based on ag-grid.
Note: This component is still in alpha stage. Major changes may still be introduced in the future.
Here is a (non-exhaustive) list of features that <DatagridAG>
offers:
- In place editing of cells or rows
- Advanced filtering
- Multi-column sorting
- Columns resizing and reordering
- Automatic page size
- Automatic column size
- Themes
- Row selection and bulk actions
- Compatibility with React Admin fields
Additionally, <DatagridAG>
is compatible with the Enterprise version of ag-grid, which offers even more features:
- Row Grouping
- Aggregation
- Tree Data
- Pivoting
- More advanced filtering
- Master Detail views
- Range Selection
- Excel Export
- And more...
You can test it live in the Enterprise Edition Storybook.
Installation
npm install --save @react-admin/ra-datagrid-ag
# or
yarn add @react-admin/ra-datagrid-ag
Tip: ra-datagrid-ag
is part of the React-Admin Enterprise Edition, and hosted in a private npm registry. You need to subscribe to one of the Enterprise Edition plans to access this package.
<DatagridAG>
<DatagridAG>
is an alternative datagrid component with advanced features, based on ag-grid.
Usage
Use <DatagridAG>
as a child of a react-admin <List>
, <ReferenceManyField>
, or any other component that creates a ListContext
.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
Here are the important things to note:
- You need to import the ag-grid stylesheets
ag-grid.css
andag-theme-alpine.css
. - To benefit from ag-grid's filtering and sorting features (as well as some Enterprise features like grouping), you need to load the entire list of records client-side. To do so, you must set
<List perPage>
to a high number (e.g. 10,000). - As the pagination is handled by ag-grid, you can disable react-admin's pagination with
<List pagination={false}>
. - The columns are defined using the
columnDefs
prop. See the dedicated doc section for more information.
<DatagridAG>
doesn't currently support the server-side row model, so you have to load all data client-side. The client-side performance isn't affected by a large number of records, as ag-grid uses DOM virtualization. <DatagridAG>
has been tested with 10,000 records without any performance issue.
Props
Prop | Required | Type | Default | Description |
---|---|---|---|---|
columnDefs |
Required | Array | n/a | The columns definitions |
bulkActionButtons |
Optional | Element | <BulkDelete Button> |
The component used to render the bulk action buttons |
cellRenderer |
Optional | String, Function or Element | Allows to use a custom component to render the cell content | |
darkTheme |
Optional | String | 'ag-theme-alpine-dark' |
The name of the ag-grid dark theme |
defaultColDef |
Optional | Object | The default column definition (applied to all columns) | |
mutationOptions |
Optional | Object | The mutation options | |
preferenceKey |
Optional | String or false |
${resource}.ag-grid.params |
The key used to persist gridState in the Store. false disables persistence. |
sx |
Optional | Object | The sx prop passed down to the wrapping <div> element |
|
theme |
Optional | String | 'ag-theme-alpine' |
The name of the ag-grid theme |
pagination |
Optional | Boolean | true |
Enable or disable pagination |
<DatagridAG>
also accepts the same props as <AgGridReact>
with the exception of rowData
, since the data is fetched from the List context.
Defaults
Under the hood, <DatagridAG>
is a wrapper around <AgGridReact>
. However it sets some important default values:
pagination
is set totrue
paginationAutoPageSize
is set totrue
animateRows
is set totrue
rowSelection
is set to'multiple'
suppressRowClickSelection
is set totrue
readOnlyEdit
is set totrue
getRowId
is set to use the recordid
field
It also register the following default modules: ClientSideRowModelModule
, CommunityFeaturesModule
and CsvExportModule
. If you wish to add custom modules, make sure you have at least one RowModel module such as ClientSideRowModelModule
or InfiniteRowModelModule
:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
import { CsvExportModule } from '@ag-grid-community/csv-export';
import { ClipboardModule } from '@ag-grid-enterprise/clipboard';
const modules = [ClientSideRowModelModule, CsvExportModule, ClipboardModule];
export const PostList = () => {
const columnDefs = [
{
field: 'id',
editable: false,
headerCheckboxSelection: true,
checkboxSelection: true,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: 'title' },
{
field: 'published_at',
headerName: 'Publication Date',
},
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} modules={modules} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
import { ClientSideRowModelModule } from "@ag-grid-community/client-side-row-model";
import { CsvExportModule } from "@ag-grid-community/csv-export";
import { ClipboardModule } from "@ag-grid-enterprise/clipboard";
const modules = [ClientSideRowModelModule, CsvExportModule, ClipboardModule];
export const PostList = () => {
const columnDefs = [
{
field: "id",
editable: false,
headerCheckboxSelection: true,
checkboxSelection: true,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: "title" },
{
field: "published_at",
headerName: "Publication Date",
},
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} modules={modules} />
</List>
);
};
It also includes a defaultColDef
object with the following properties:
{
resizable: true,
filter: true,
sortable: true,
editable: true,
headerCheckboxSelectionFilteredOnly: true,
headerCheckboxSelectionCurrentPageOnly: true,
}
You may override any of these defaults by passing the corresponding props to <DatagridAG>
(defaultColDef
will be merged with the defaults).
bulkActionButtons
You can use the bulkActionButtons
prop to customize the bulk action buttons, displayed when at least one row is selected.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List, BulkExportButton, BulkDeleteButton } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
const PostBulkActionButtons = () => (
<>
<BulkExportButton />
<BulkDeleteButton />
</>
);
export const PostList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
bulkActionButtons={<PostBulkActionButtons />}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List, BulkExportButton, BulkDeleteButton } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
const PostBulkActionButtons = () => (
<>
<BulkExportButton />
<BulkDeleteButton />
</>
);
export const PostList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: "title" },
{ field: "published_at" },
{ field: "body" },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} bulkActionButtons={<PostBulkActionButtons />} />
</List>
);
};
cellRenderer
In a column definition, you can use the cellRenderer
field to specify a custom cell renderer. In addition to ag-grid's cell rendering abilities, <DatagridAG>
supports react-admin fields in cellRenderer
. This is particularly useful to render a <ReferenceField>
for instance.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { EmailField, List, ReferenceField, TextField } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const CommentList = () => {
const columnDefs = [
{
field: 'id',
editable: false,
},
{ field: 'author.name' },
{
field: 'author.email',
cellRenderer: <EmailField source="author.email" />,
},
{
field: 'post_id',
headerName: 'Post',
cellRenderer: (
<ReferenceField source="post_id" reference="posts">
<TextField source="title" />
</ReferenceField>
),
},
{ field: 'created_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { EmailField, List, ReferenceField, TextField } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const CommentList = () => {
const columnDefs = [
{
field: "id",
editable: false,
},
{ field: "author.name" },
{
field: "author.email",
cellRenderer: <EmailField source="author.email" />,
},
{
field: "post_id",
headerName: "Post",
cellRenderer: (
<ReferenceField source="post_id" reference="posts">
<TextField source="title" />
</ReferenceField>
),
},
{ field: "created_at" },
{ field: "body" },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
Note: You still need to pass the source
prop to the field.
columnDefs
The columnDefs
prop is the most important prop of <DatagridAG>
. It defines the columns of the grid, and their properties. It is an array of objects, each object representing a column.
Here is an example with a complete column definitions object:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
const truncate = (str: string, n: number) => {
return str.length > n ? str.slice(0, n - 1) + '...' : str;
};
export const PostList = () => {
const columnDefs = [
{
field: 'id',
editable: false,
headerCheckboxSelection: true,
checkboxSelection: true,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: 'title' },
{
field: 'published_at',
headerName: 'Publication Date',
},
{
field: 'body',
cellRenderer: ({ value }) => truncate(value, 20),
},
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
const truncate = (str, n) => {
return str.length > n ? str.slice(0, n - 1) + "..." : str;
};
export const PostList = () => {
const columnDefs = [
{
field: "id",
editable: false,
headerCheckboxSelection: true,
checkboxSelection: true,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: "title" },
{
field: "published_at",
headerName: "Publication Date",
},
{
field: "body",
cellRenderer: ({ value }) => truncate(value, 20),
},
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
Have a look at the ag-grid documentation for the exhaustive list of column properties.
darkTheme
You can use a different dark theme for the grid by passing a darkTheme
prop. It will be applied automatically whenever React Admin theme is set to dark.
You can for instance use one of the themes provided by ag-grid, like ag-theme-balham
or ag-theme-alpine-dark
:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-balham.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
theme="ag-theme-balham"
darkTheme="ag-theme-balham-dark"
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-balham.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} theme="ag-theme-balham" darkTheme="ag-theme-balham-dark" />
</List>
);
};
Tip: Remember to import the corresponding stylesheet (e.g. ag-theme-balham[.min].css
for ag-theme-balham
).
defaultColDef
The defaultColDef
prop allows you to define default properties for all columns. It is an object with the same properties as columnDefs
objects.
In the example below, we enable flex mode on the columns, and set each column to take 1/3 of the available space:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} />
</List>
);
};
mutationOptions
You can use the mutationOptions
prop to provide options to the dataProvider.update()
call triggered when a cell or a row is edited.
In particular, this allows to choose the mutationMode
, and/or to pass a meta
object to the dataProvider.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
mutationOptions={{
meta: { foo: 'bar' },
mutationMode: 'optimistic',
}}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
mutationOptions={{
meta: { foo: "bar" },
mutationMode: "optimistic",
}}
/>
</List>
);
};
This also allows to display a notification after the mutation succeeds.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List, useNotify } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
const notify = useNotify();
const onSuccess = React.useCallback(() => {
notify('ra.notification.updated', {
type: 'info',
messageArgs: {
smart_count: 1,
},
undoable: true,
});
}, [notify]);
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
mutationOptions={{
mutationMode: 'undoable',
onSuccess,
}}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List, useNotify } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
const notify = useNotify();
const onSuccess = React.useCallback(() => {
notify("ra.notification.updated", {
type: "info",
messageArgs: {
smart_count: 1,
},
undoable: true,
});
}, [notify]);
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
mutationOptions={{
mutationMode: "undoable",
onSuccess,
}}
/>
</List>
);
};
pagination
By default, the pagination
prop is set to true
, so that the records are paginated.
If you would like to view all the records at once, you can set the pagination
prop to false
. Thanks to ag-grid's DOM virtualization, you will be able to scroll across all of them with no performance issues.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
const CarList = () => {
const columnDefs = [
{ field: 'make' },
{ field: 'model' },
{ field: 'price' },
];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
pagination={false}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
const CarList = () => {
const columnDefs = [{ field: "make" }, { field: "model" }, { field: "price" }];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} pagination={false} />
</List>
);
};
If you have subscribed to the Enterprise version of ag-grid, you can also add a Status Bar to show the total number of rows.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React, { useMemo } from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
import 'ag-grid-enterprise';
const CarList = () => {
const statusBar = useMemo(() => {
return {
statusPanels: [
{
statusPanel: 'agTotalAndFilteredRowCountComponent',
align: 'left',
},
],
};
}, []);
const columnDefs = [
{ field: 'make' },
{ field: 'model' },
{ field: 'price' },
];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
pagination={false}
statusBar={statusBar}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React, { useMemo } from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
import "ag-grid-enterprise";
const CarList = () => {
const statusBar = useMemo(() => {
return {
statusPanels: [
{
statusPanel: "agTotalAndFilteredRowCountComponent",
align: "left",
},
],
};
}, []);
const columnDefs = [{ field: "make" }, { field: "model" }, { field: "price" }];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
pagination={false}
statusBar={statusBar}
/>
</List>
);
};
preferenceKey
<DatagridAG>
will store the gridState
in the Store, under the key ${resource}.ag-grid.params.grid
. This gridState
persisted in the store is applied once when the grid is created, it means that users will find the grid as they left it previously.
If you wish to change the key used to store the columns order and size, you can pass a preferenceKey
prop to <DatagridAG>
.
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} preferenceKey="my-post-list" />
</List>
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} preferenceKey="my-post-list" />
</List>;
If, instead, you want to disable the persistence of the columns order and size, you can pass false
to the preferenceKey
prop:
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} preferenceKey={false} />
</List>
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} preferenceKey={false} />
</List>;
Tip: If you update the columnDefs
prop, make sure to clear or invalidate the React-admin store in order to view your changes.
sx
You can also use the sx
prop to customize the grid's style:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
sx={{ '& .ag-header-cell-comp-wrapper': { color: 'red' } }}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} sx={{ "& .ag-header-cell-comp-wrapper": { color: "red" } }} />
</List>
);
};
It can also be helpful to change the default grid's height (calc(100vh - 96px - ${theme.spacing(1)})
):
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
/* ... */
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
sx={{ height: 'calc(100vh - 250px)' }}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [
/* ... */
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} sx={{ height: "calc(100vh - 250px)" }} />
</List>
);
};
theme
You can use a different theme for the grid by passing a theme
prop. You can for instance use one of the themes provided by ag-grid, like ag-theme-balham
or ag-theme-alpine-dark
:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-balham.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} theme="ag-theme-balham" />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-balham.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} theme="ag-theme-balham" />
</List>
);
};
Tip: Remember to import the corresponding stylesheet (e.g. ag-theme-balham[.min].css
for ag-theme-balham
).
Accessing The Grid API
You can access the grid's api
by passing a ref
to <DatagridAG>
.
In this example, we use the api
to automatically resize all columns to fit their content on first render:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { AgGridReact } from 'ag-grid-react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
const gridRef = React.useRef<AgGridReact>(null);
const onFirstDataRendered = React.useCallback(() => {
gridRef.current.api.autoSizeAllColumns();
}, []);
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
ref={gridRef}
onFirstDataRendered={onFirstDataRendered}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
const gridRef = React.useRef(null);
const onFirstDataRendered = React.useCallback(() => {
gridRef.current.api.autoSizeAllColumns();
}, []);
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} ref={gridRef} onFirstDataRendered={onFirstDataRendered} />
</List>
);
};
Check out the Grid API documentation to learn more.
Changing The Default Column Width
By default, ag-grid will render each column with a fixed size.
You can choose to enable flex mode by setting the flex
prop either on the columnDefs
or on the defaultColDef
:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at', flex: 1 },
{ field: 'body' },
];
const defaultColDef = {
flex: 2,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at", flex: 1 }, { field: "body" }];
const defaultColDef = {
flex: 2,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} />
</List>
);
};
Alternatively, you can use the grid's api
to call autoSizeAllColumns
to automatically resize all columns to fit their content:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { AgGridReact } from 'ag-grid-react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
const gridRef = React.useRef<AgGridReact>(null);
const onFirstDataRendered = React.useCallback(() => {
gridRef.current.api.autoSizeAllColumns();
}, []);
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
ref={gridRef}
onFirstDataRendered={onFirstDataRendered}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
const gridRef = React.useRef(null);
const onFirstDataRendered = React.useCallback(() => {
gridRef.current.api.autoSizeAllColumns();
}, []);
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} ref={gridRef} onFirstDataRendered={onFirstDataRendered} />
</List>
);
};
Check out the Column Sizing documentation for more information and more alternatives.
Selecting Rows And Enabling Bulk Actions
Just like <Datagrid>
, <DatagridAG>
supports row selection and bulk actions.
Add a column with the following definition to enable row selection:
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
Below is an example with the PostList
component:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: "title" },
{ field: "published_at" },
{ field: "body" },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
Just like with <Datagrid>
, you can customize the bulk actions by passing a bulkActionButtons
prop to <DatagridAG>
.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List, BulkExportButton, BulkDeleteButton } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
const PostBulkActionButtons = () => (
<>
<BulkExportButton />
<BulkDeleteButton />
</>
);
export const PostList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
bulkActionButtons={<PostBulkActionButtons />}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List, BulkExportButton, BulkDeleteButton } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
const PostBulkActionButtons = () => (
<>
<BulkExportButton />
<BulkDeleteButton />
</>
);
export const PostList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: "title" },
{ field: "published_at" },
{ field: "body" },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} bulkActionButtons={<PostBulkActionButtons />} />
</List>
);
};
Enabling Infinite Pagination
By default, <DatagridAG>
renders pagination controls at the bottom of the list. You can disable these controls to switch to an infinite pagination mode, where the grid shows the next rows on scroll. Thanks to ag-grid's DOM virtualization, this mode causes no performance problem.
To enable infinite pagination, set the pagination
prop to false
.
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
const CarList = () => {
const columnDefs = [
{ field: 'make' },
{ field: 'model' },
{ field: 'price' },
];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
pagination={false}
/>
</List>
);
};
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
const CarList = () => {
const columnDefs = [{ field: "make" }, { field: "model" }, { field: "price" }];
const defaultColDef = {
flex: 1,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} pagination={false} />
</List>
);
};
If you have subscribed to the Enterprise version of ag-grid, you can also add a Status Bar to show the total number of rows.
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
import React, { useMemo } from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
import 'ag-grid-enterprise';
const CarList = () => {
const statusBar = useMemo(() => {
return {
statusPanels: [
{
statusPanel: 'agTotalAndFilteredRowCountComponent',
align: 'left',
},
],
};
}, []);
const columnDefs = [{ field: 'make' }, { field: 'model' }, { field: 'price' }];
const defaultColDef = { flex: 1 };
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
pagination={false}
statusBar={statusBar}
/>
</List>
);
};
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import React, { useMemo } from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
import "ag-grid-enterprise";
const CarList = () => {
const statusBar = useMemo(() => {
return {
statusPanels: [
{
statusPanel: "agTotalAndFilteredRowCountComponent",
align: "left",
},
],
};
}, []);
const columnDefs = [{ field: "make" }, { field: "model" }, { field: "price" }];
const defaultColDef = { flex: 1 };
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
pagination={false}
statusBar={statusBar}
/>
</List>
);
};
Enabling Full Row Edition
By default, editing is enabled on cells, which means you can edit a cell by double-clicking on it, and it will trigger a call to the dataProvider's update
function.
However, if you'd like to update the full row at once instead, you can enable full row editing by passing editType="fullRow"
to <DatagridAG>
:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
/* ... */
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} editType="fullRow" />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [
/* ... */
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} editType="fullRow" />
</List>
);
};
Disabling Cell Edition
Set editable: false
in the definition of a column to disable the ability to edit its cells.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at', editable: false },
{ field: 'body' },
];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at", editable: false }, { field: "body" }];
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} />
</List>
);
};
Alternatively, you can disable the ability to edit all cells by passing editable: false
to the defaultColDef
:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const columnDefs = [
{ field: 'title' },
{ field: 'published_at' },
{ field: 'body' },
];
const defaultColDef = {
editable: false,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} />
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const columnDefs = [{ field: "title" }, { field: "published_at" }, { field: "body" }];
const defaultColDef = {
editable: false,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG columnDefs={columnDefs} defaultColDef={defaultColDef} />
</List>
);
};
Using AG Grid Enterprise
<DatagridAG>
is also compatible with the Enterprise version of ag-grid.
You can follow the instructions in the Getting Started with AG Grid Enterprise section of the Getting Started documentation to enable the Enterprise features.
Below is a short example of what you can achieve.
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-enterprise';
import React from 'react';
import { List } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
const OlympicWinnersList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: 'athlete' },
{ field: 'age' },
{ field: 'country' },
{ field: 'year' },
{ field: 'date' },
{ field: 'sport' },
{ field: 'gold' },
{ field: 'silver' },
{ field: 'bronze' },
{ field: 'total' },
];
const gridRef = React.useRef<AgGridReact>(null);
const onFirstDataRendered = React.useCallback(() => {
gridRef.current.api.autoSizeAllColumns();
}, []);
const defaultColDef = {
enableRowGroup: true,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
ref={gridRef}
onFirstDataRendered={onFirstDataRendered}
rowGroupPanelShow="always"
groupSelectsChildren
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import "ag-grid-enterprise";
import React from "react";
import { List } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
const OlympicWinnersList = () => {
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: "athlete" },
{ field: "age" },
{ field: "country" },
{ field: "year" },
{ field: "date" },
{ field: "sport" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
{ field: "total" },
];
const gridRef = React.useRef(null);
const onFirstDataRendered = React.useCallback(() => {
gridRef.current.api.autoSizeAllColumns();
}, []);
const defaultColDef = {
enableRowGroup: true,
};
return (
<List perPage={10000} pagination={false}>
<DatagridAG
columnDefs={columnDefs}
defaultColDef={defaultColDef}
ref={gridRef}
onFirstDataRendered={onFirstDataRendered}
rowGroupPanelShow="always"
groupSelectsChildren
/>
</List>
);
};
Adding An Expandable Panel (Master/Detail)
You can leverage ag-grid Master Detail Module to add an expandable panel.
For instance, here's how to show the comments of a post in an expandable panel:
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import { AgGridReact } from 'ag-grid-react';
import { ColDef, CommunityFeaturesModule } from '@ag-grid-community/core';
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
import { CsvExportModule } from '@ag-grid-community/csv-export';
import { MasterDetailModule } from '@ag-grid-enterprise/master-detail';
import React from 'react';
import { List, useDataProvider, useNotify } from 'react-admin';
import { DatagridAG } from '@react-admin/ra-datagrid-ag';
export const PostList = () => {
const dataProvider = useDataProvider();
const notify = useNotify();
const columnDefs: ColDef<any, any>[] = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: 'title', flex: 1, cellRenderer: 'agGroupCellRenderer' },
{ field: 'published_at' },
];
const detailCellRendererParams = {
// provide the Grid Options to use on the Detail Grid
detailGridOptions: {
columnDefs: [{ field: 'body', flex: 1 }, { field: 'author.name' }],
},
// get the rows for each Detail Grid
getDetailRowData: params => {
dataProvider
.getManyReference('comments', {
target: 'post_id',
id: params.data.id,
pagination: { page: 1, perPage: 100 },
sort: { field: 'created_at', order: 'DESC' },
filter: {},
})
.then(({ data }) => {
params.successCallback(data);
})
.catch(error => {
notify(error.message, { type: 'error' });
params.successCallback([]);
});
},
};
return (
<List resource="posts" pagination={false}>
<DatagridAG
masterDetail
columnDefs={columnDefs}
detailCellRendererParams={detailCellRendererParams}
pagination={false}
modules={[
ClientSideRowModelModule,
CommunityFeaturesModule,
CsvExportModule,
MasterDetailModule,
]}
/>
</List>
);
};
import "@ag-grid-community/styles/ag-grid.css";
import "@ag-grid-community/styles/ag-theme-alpine.css";
import { CommunityFeaturesModule } from "@ag-grid-community/core";
import { ClientSideRowModelModule } from "@ag-grid-community/client-side-row-model";
import { CsvExportModule } from "@ag-grid-community/csv-export";
import { MasterDetailModule } from "@ag-grid-enterprise/master-detail";
import React from "react";
import { List, useDataProvider, useNotify } from "react-admin";
import { DatagridAG } from "@react-admin/ra-datagrid-ag";
export const PostList = () => {
const dataProvider = useDataProvider();
const notify = useNotify();
const columnDefs = [
{
headerCheckboxSelection: true,
checkboxSelection: true,
editable: false,
minWidth: 48,
maxWidth: 48,
suppressColumnsToolPanel: true,
suppressHeaderFilterButton: true,
},
{ field: "title", flex: 1, cellRenderer: "agGroupCellRenderer" },
{ field: "published_at" },
];
const detailCellRendererParams = {
// provide the Grid Options to use on the Detail Grid
detailGridOptions: {
columnDefs: [{ field: "body", flex: 1 }, { field: "author.name" }],
},
// get the rows for each Detail Grid
getDetailRowData: (params) => {
dataProvider
.getManyReference("comments", {
target: "post_id",
id: params.data.id,
pagination: { page: 1, perPage: 100 },
sort: { field: "created_at", order: "DESC" },
filter: {},
})
.then(({ data }) => {
params.successCallback(data);
})
.catch((error) => {
notify(error.message, { type: "error" });
params.successCallback([]);
});
},
};
return (
<List resource="posts" pagination={false}>
<DatagridAG
masterDetail
columnDefs={columnDefs}
detailCellRendererParams={detailCellRendererParams}
pagination={false}
modules={[ClientSideRowModelModule, CommunityFeaturesModule, CsvExportModule, MasterDetailModule]}
/>
</List>
);
};
CHANGELOG
v5.0.0
2024-07-25
- Upgrade to react-admin v5
- Upgrade to ag-grid v32
<DatagridAG>
now applies react-admin theme even when it changes (light to dark)<DatagridAG>
now accepts adarkTheme
prop.- [TypeScript]: Enable strictNullChecks
v4.1.0
2023-12-22
- Feat: persist grid state in the react-admin store and apply it through the
initialState
prop
v4.0.1
2023-12-07
- Disable lazy loading for
<DatagridAG>
as it is no longer necessary since<DatagridAG>
now has its own package. - Add a story to demonstrate
ag-grid-enterprise
- Bump to
ag-grid
v31
v4.0.0
2023-11-21
- Initial release