Skip to contents

Column Definition

Column definitions in the Data Grid specify how data is displayed, formatted, and interacted with. Each column has a unique field name and various properties that control its behavior.

Core Properties

field

The unique identifier for the column (required). Must match a field in the row data.

DataGrid() internally handles the mandatory "id" argument required by MUI Data Grid. If the dataset does not contain an "id" column, one is automatically added based on row number using nrow(). If an "id" column already exists in the dataset, it is used as-is.

Warning: If your dataframe already contains an "id" column, each value must be unique — duplicate IDs will cause unexpected behavior in the grid.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name"),
    list(field = "height"),
    list(field = "mass")
  )
)

headerName

The text displayed in the column header. Defaults to the field name if not specified.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", headerName = "Character Name"),
    list(field = "height", headerName = "Height (cm)"),
    list(field = "mass", headerName = "Weight (kg)")
  )
)

description

Tooltip text shown when hovering over the column header.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(
      field = "name",
      headerName = "Name",
      description = "The character's full name"
    ),
    list(
      field = "height",
      headerName = "Height",
      description = "Height in centimeters"
    ),
    list(
      field = "mass",
      headerName = "Mass",
      description = "Weight in kilograms"
    )
  )
)

type

The column type affects formatting and default behavior. Available types: - "string" (default) - "number" - "date" - "dateTime" - "boolean" - "singleSelect"

starwars_typed <- starwars |>
  select(name, height, birth_year) |>
  mutate(is_tall = height > 180) |>
  head()

DataGrid(
  rows = starwars_typed,
  columns = list(
    list(field = "name", type = "string", headerName = "Name", width = 200),
    list(field = "height", type = "number", headerName = "Height", width = 120),
    list(field = "birth_year", type = "number", headerName = "Birth Year", width = 120),
    list(field = "is_tall", type = "boolean", headerName = "Tall?", width = 100)
  )
)

Date and dateTime columns

Dates need special handling. The Data Grid does not auto-detect a date type from your data, and — just as importantly — R Date and POSIXct values are not transmitted to the browser as readable date strings. When a data frame is serialized, each Date cell loses its class and is sent as a bare number (days since 1970-01-01), and POSIXct is sent as seconds since the epoch. A date column fed that number renders as 1/1/1970, because the browser interprets it as milliseconds since the epoch.

The reliable pattern is therefore to convert your dates to ISO 8601 character strings in R first, then declare the column type = "date" (or "dateTime") and add a valueGetter that turns the string back into a JavaScript Date:

events <- data.frame(
  event = c("A New Hope", "The Empire Strikes Back", "Return of the Jedi"),
  release = as.Date(c("1977-05-25", "1980-05-21", "1983-05-25")),
  stringsAsFactors = FALSE
)

events$release <- format(events$release)  # ISO strings: "1977-05-25"

DataGrid(
  rows = events,
  columns = list(
    list(field = "event", headerName = "Film", width = 220),
    list(
      field = "release",
      headerName = "Release Date",
      type = "date",
      width = 160,
      valueGetter = JS("function(value) { return value ? new Date(value) : null; }")
    )
  )
)

The valueGetter is what makes MUI’s date-picker filter operators (after, before, onOrAfter, …) and locale-aware valueFormatter formatting work.

For timestamps, format to an ISO date-time string and use type = "dateTime":

logs <- data.frame(
  message = c("Started", "Finished"),
  ts = as.POSIXct(c("2024-03-15 09:30:00", "2024-03-15 17:45:00"), tz = "UTC"),
  stringsAsFactors = FALSE
)

logs$ts <- format(logs$ts, "%Y-%m-%dT%H:%M:%SZ")  # "2024-03-15T09:30:00Z"

DataGrid(
  rows = logs,
  columns = list(
    list(field = "message", headerName = "Event", width = 160),
    list(
      field = "ts",
      headerName = "Timestamp",
      type = "dateTime",
      width = 200,
      valueGetter = JS("function(value) { return value ? new Date(value) : null; }")
    )
  )
)

If you only need dates displayed and sorted (no date-picker filter), the simplest option is to keep them as ISO character strings and leave the column as the default "string" type — ISO strings already sort chronologically.

Display Properties

width

Fixed column width in pixels.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", width = 250),
    list(field = "height", width = 120),
    list(field = "mass", width = 120)
  )
)

flex

Flexible column width as a proportion of available space. Cannot be used with width.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", flex = 2),
    list(field = "height", flex = 1),
    list(field = "mass", flex = 1)
  )
)

minWidth / maxWidth

Constraints for column width when using flex or resizing.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", flex = 1, minWidth = 150),
    list(field = "height", flex = 1, minWidth = 80, maxWidth = 120),
    list(field = "mass", flex = 1, minWidth = 80, maxWidth = 120)
  )
)

align / headerAlign

Text alignment for cell content and header.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(
      field = "name", 
      headerAlign = "left", 
      align = "left", 
      width = 200
    ),
    list(
      field = "height", 
      headerAlign = "center", 
      align = "right", 
      width = 120
    ),
    list(
      field = "mass", 
      headerAlign = "center", 
      align = "right", 
      width = 120
    )
  )
)

hide

Hide a column while keeping it in the data.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", width = 200),
    list(field = "height", width = 120),
    list(field = "mass", width = 120, hide = TRUE),
    list(field = "species", width = 150)
  )
)

Interaction Properties

sortable

Enable or disable sorting for the column (default: TRUE).

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", sortable = TRUE, width = 200),
    list(field = "height", sortable = TRUE, width = 120),
    list(field = "mass", sortable = FALSE, width = 120)
  )
)

filterable

Enable or disable filtering for the column (default: TRUE).

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", filterable = TRUE, width = 200),
    list(field = "height", filterable = TRUE, width = 120),
    list(field = "mass", filterable = FALSE, width = 150)
  )
)

editable

Make the column editable (default: FALSE).

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", editable = FALSE, width = 200),
    list(field = "height", editable = TRUE, width = 120),
    list(field = "mass", editable = TRUE, width = 120)
  )
)

resizable

Enable column resizing by dragging borders (default: TRUE).

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", resizable = TRUE, width = 200),
    list(field = "height", resizable = TRUE, width = 120),
    list(field = "mass", resizable = FALSE, width = 120)
  )
)

Value Formatting

valueFormatter

Format the displayed value without changing the underlying data.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", width = 200),
    list(
      field = "height",
      headerName = "Height",
      width = 150,
      valueFormatter = JS("function(value) { return value ? value + ' cm' : 'Unknown'; }")
    ),
    list(
      field = "mass",
      headerName = "Mass",
      width = 150,
      valueFormatter = JS("function(value) { return value ? value + ' kg' : 'Unknown'; }")
    )
  )
)

valueGetter

Compute or derive values from row data.

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name", width = 150),
    list(field = "height", width = 100),
    list(field = "mass", width = 100),
    list(
      field = "bmi",
      headerName = "BMI",
      width = 100,
      type = "number",
      valueGetter = JS("
        function(value, row) {
          if (row.height && row.mass) {
            const heightInM = row.height / 100;
            return Math.round(row.mass / (heightInM * heightInM) * 10) / 10;
          }
          return null;
        }
      ")
    )
  )
)

valueSetter

Control how edited values are stored (for editable columns):

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(field = "name"),
    list(
      field = "height",
      editable = TRUE,
      valueSetter = JS("
        function(value, row) {
          const numValue = Number(value);
          if (!isNaN(numValue) && numValue > 0) {
            row.height = numValue;
            return row;
          }
          return row; // Return unchanged if invalid
        }
      ")
    ),
    list(field = "mass")
  )
)

Advanced Properties

renderCell

Custom cell rendering with React components:

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(
      field = "name",
      renderCell = JS("
        function(params) {
          return React.createElement('strong', {}, params.value);
        }
      ")
    ),
    list(field = "height"),
    list(field = "mass")
  )
)

renderHeader

Custom header rendering:

DataGrid(
  rows = starwars |> select(name, height, mass) |> head(),
  columns = list(
    list(
      field = "name",
      renderHeader = JS("
        function(params) {
          return React.createElement('strong', {}, params.colDef.headerName || params.field);
        }
      ")
    ),
    list(field = "height"),
    list(field = "mass")
  )
)

Column Grouping

Group multiple columns under a common header:

DataGrid(
  rows = starwars |> 
    select(name, height, mass, hair_color, skin_color) |> 
    head(),
  columns = list(
    list(field = "name"),
    list(field = "height"),
    list(field = "mass"),
    list(field = "hair_color"),
    list(field = "skin_color")
  ),
  columnGroupingModel = list(
    list(
      groupId = "physical",
      headerName = "Physical Attributes",
      children = list(
        list(field = "height"),
        list(field = "mass")
      )
    ),
    list(
      groupId = "appearance",
      headerName = "Appearance",
      children = list(
        list(field = "hair_color"),
        list(field = "skin_color")
      )
    )
  )
)

Complete Example

Here’s a comprehensive example using many column properties:

DataGrid(
  rows = starwars |> select(name, height, mass, hair_color, skin_color) |> head(10),
  columns = list(
    list(
      field = "name",
      headerName = "Character Name",
      description = "Name of the Star Wars character",
      width = 180,
      sortable = TRUE,
      filterable = TRUE,
      hideable = FALSE,
      pinnable = TRUE,
      align = "left"
    ),
    list(
      field = "height",
      headerName = "Height",
      description = "Height in centimeters",
      type = "number",
      width = 100,
      align = "center",
      headerAlign = "center",
      valueFormatter = JS("function(value) { return value ? value + ' cm' : 'N/A'; }")
    ),
    list(
      field = "mass",
      headerName = "Mass",
      description = "Mass in kilograms",
      type = "number",
      width = 100,
      align = "center",
      headerAlign = "center",
      valueFormatter = JS("function(value) { return value ? value + ' kg' : 'N/A'; }")
    )
  ),
  initialState = list(
    pagination = list(
      paginationModel = list(pageSize = 5)
    )
  )
)