DataGrid - Admin Components

Note: This component is available since Medusa v2.21.0.

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.

Code
import {
  DataGrid,
  createDataGridHelper,
} from "@medusajs/dashboard/components"

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:

src/admin/routes/variants/page.tsx
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 to FieldValues.

You rarely set them explicitly. TypeScript infers TData from the columns and data props, and TFieldValues from the state prop:

Code
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:

Code
const columnHelper = createDataGridHelper<
  HttpTypes.AdminProductVariant,
  PricesForm
>()

createDataGridHelper takes the same two type arguments, so set them there and the grid infers the rest:

Code
<DataGrid
  columns={columns}
  data={variants}
  state={form}
/>

To set the type arguments explicitly, pass them when you use the component:

Code
<DataGrid<HttpTypes.AdminProductVariant, PricesForm>
  columns={columns}
  data={variants}
  state={form}
/>

Props#

DataGrid accepts the DataGridProps type, which extends DataGridRootProps:

columnsColumnDef<TData>[]
The grid's columns. Create them with createDataGridHelper or createDataGridPriceColumns, which also set the TData and TFieldValues type arguments.
dataTData[]Optional
The records to show in the grid. TData is the row type.
stateUseFormReturn<TFieldValues>
The react-hook-form form that holds the grid's values. TFieldValues is the form's value type.
isLoadingbooleanOptional
Whether the grid shows its loading skeleton instead of the grid.
getSubRows(row: TData) => TData[] | undefinedOptional
Returns the sub-rows of a row, such as a product's variants, where TData is the row type.
onEditingChange(isEditing: boolean) => voidOptional
A function that runs when the user starts or stops editing a cell. Use it to prevent a modal from closing while the user edits a cell.
disableInteractionsbooleanOptional
Whether to disable the grid's keyboard navigation and selection.
multiColumnSelectionbooleanOptional
Whether the user can select cells across more than one column.
showColumnsDropdownbooleanOptional
Whether to show the dropdown that toggles the grid's columns.
headerContentReactNodeOptional
Custom content shown in the grid's header, between the column controls and the error section.
totalRowCountnumberOptional
The total number of rows. Pass it to enable lazy loading, where the grid fetches more rows as the user scrolls.
onFetchMore() => voidOptional
A function that runs when the grid needs to fetch more rows in lazy loading mode.
isFetchingMorebooleanOptional
Whether the grid is currently fetching more rows.
hasNextPagebooleanOptional
Whether there are more rows to fetch.

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

DataGrid.TextCell

Edits the cell's value in a single-line text input.

DataGrid.MultilineCell

Edits the cell's value in a multi-line text input.

DataGrid.ExpandableTextCell

Edits long text. The user can expand the cell into a modal.

DataGrid.NumberCell

Edits the cell's value in a number input. It also accepts the min and max props.

DataGrid.CurrencyCell

Edits a price. It also accepts a code prop, which is the currency's code.

DataGrid.BooleanCell

Edits the cell's value with a checkbox. It also accepts a disabled prop.

DataGrid.ReadonlyCell

Shows its children in a cell that the user can't edit.


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.

Code
const columnHelper = createDataGridHelper<
  Variant,
  VariantsFormValues
>()

For example, the following column shows a variant's title in an editable text cell:

Code
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:

idstring
The column's ID.
headerstring | (context) => ReactNode
The column's header. Pass a string to show it as plain text, or a function to render custom content.
cellstring | (context) => ReactNode
The cell's content. Pass a function that returns one of the cell components, and pass the function's context to that component so it can read and edit the cell's value.
namestringOptional
The column's name, shown in the column visibility menu.
field(context: FieldContext<TData>) => FieldPath<TFieldValues> | nullOptional
Returns the path of the form field that the cell edits, where TData and TFieldValues are the type arguments. Return null, or omit the property, to make the cell read-only. Pass type with it.
type"text" | "multiline-text" | "number" | "boolean" | "togglable-number"Optional
The type of value the cell holds. It's required when you pass field, and not allowed otherwise.
disableHidingbooleanOptional
Whether the user can't hide the column.

Default: false

sizenumberOptional
The column's size in pixels.
minSizenumberOptional
The column's minimum size in pixels.
maxSizenumberOptional
The column's maximum size in pixels.

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.

Code
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:

getFieldName(context: FieldContext<TData>, value: string) => FieldPath<TFieldValues> | null
Returns the path of the form field that a price cell edits, where TData and TFieldValues are the type arguments. value is the currency's code or the region's ID.
tTFunction
The translation function returned by useTranslation of react-i18next, used for the columns' names.
currenciesstring[]Optional
The currency codes to create a column for. Each column's ID is currency_prices.{code}.
regionsAdminRegion[]Optional
The regions to create a column for. Each column's ID is region_prices.{id}.
pricePreferencesAdminPricePreference[]Optional
The price preferences, used to show whether a column's prices include taxes.
isReadyOnly(context: FieldContext<TData>) => booleanOptional
Returns whether a cell is read-only, where TData is the row type. The function renders a read-only cell when it returns true.
renderPriceCell(code: string, context: CellContext<TData, any>) => ReactNodeOptional
Renders a custom price cell, where TData is the row type. If you don't pass it, the function renders a DataGrid.CurrencyCell.

  • Data Table: a read-only table for a list of records.
Found a problem with this page?Report Issue
Edited Nov 14·Edit this page