DataGrid - Admin Components
The DataGrid component shows an editable spreadsheet-like grid whose values are bound to a react-hook-form form. The Medusa Admin uses it to bulk-edit variant prices and inventory quantities.
The grid supports keyboard navigation, range selection, copying and pasting across cells, and undo and redo.
Example#
Create the grid's columns with createDataGridHelper, then pass your form to the grid's state prop:
import {
DataGrid,
createDataGridHelper,
} from "@medusajs/dashboard/components"
import { useForm } from "react-hook-form"
const columnHelper = createDataGridHelper<
Variant,
VariantsFormValues
>()
const VariantsPage = ({ variants }) => {
const form = useForm<VariantsFormValues>({
defaultValues: { variants },
})
const columns = [
columnHelper.column({
id: "title",
name: "Title",
header: "Title",
cell: (context) => (
<DataGrid.ReadonlyCell context={context}>
{context.row.original.title}
</DataGrid.ReadonlyCell>
),
}),
columnHelper.column({
id: "sku",
name: "SKU",
header: "SKU",
type: "text",
field: (context) =>
`variants.${context.row.index}.sku`,
cell: (context) => (
<DataGrid.TextCell context={context} />
),
}),
]
return (
<DataGrid
columns={columns}
data={variants}
state={form}
/>
)
}
export default VariantsPage
The field function returns the path of the form field that the cell edits. If it returns null, the cell isn't editable.
Type Arguments
DataGrid accepts two type arguments:
TData: the type of a single row in the grid.TFieldValues: the shape of the values in the react-hook-form form that the grid edits. It defaults toFieldValues.
You rarely set them explicitly. TypeScript infers TData from the columns and data props, and TFieldValues from the state prop:
import { useForm } from "react-hook-form"
import { HttpTypes } from "@medusajs/framework/types"
type PricesForm = {
variants: Record<string, Record<string, number>>
}
const form = useForm<PricesForm>()
Passing that form as state sets TFieldValues to PricesForm, and typing the columns sets TData:
createDataGridHelper takes the same two type arguments, so set them there and the grid infers the rest:
To set the type arguments explicitly, pass them when you use the component:
<DataGrid<HttpTypes.AdminProductVariant, PricesForm>
columns={columns}
data={variants}
state={form}
/>
Props#
DataGrid accepts the DataGridProps type, which extends DataGridRootProps:
Cell Components
DataGrid has the following sub-components to render a column's cells. Each of them accepts a context prop, which is the cell context that the column's cell function receives:
Component | Description |
|---|---|
| Edits the cell's value in a single-line text input. |
| Edits the cell's value in a multi-line text input. |
| Edits long text. The user can expand the cell into a modal. |
| Edits the cell's value in a number input. It also accepts the |
| Edits a price. It also accepts a |
| Edits the cell's value with a checkbox. It also accepts a |
| Shows its |
createDataGridHelper#
createDataGridHelper returns a typed helper whose column method defines a grid column. It accepts two type parameters: the type of a row, and the type of the form's values.
For example, the following column shows a variant's title in an editable text cell:
columnHelper.column({
id: "title",
name: "Title",
header: "Title",
field: (context) =>
`variants.${context.row.index}.title`,
type: "text",
cell: (context) => (
<DataGrid.TextCell context={context} />
),
})
The header and cell properties accept either a string or a function. The function receives a context object that you pass to the cell component, which uses it to read and write the cell's value.
The column method accepts an object with the following properties:
createDataGridPriceColumns#
createDataGridPriceColumns returns a price column for each of the passed currencies and regions. Use it to let the user edit prices for many currencies and regions at once.
import {
createDataGridPriceColumns,
} from "@medusajs/dashboard/components"
import { useTranslation } from "react-i18next"
const { t } = useTranslation()
const priceColumns = createDataGridPriceColumns<
Variant,
VariantsFormValues
>({
currencies: ["usd", "eur"],
regions,
pricePreferences,
getFieldName: (context, value) =>
`variants.${context.row.index}.prices.${value}`,
t,
})
It accepts an object with the following properties:
Related Components#
- Data Table: a read-only table for a list of records.