Skip to main contentSkip to docs navigation

A virtualized alternative to Table that only renders the rows currently in view, for datasets too lg to mount all at once.

Overview

DataGrid is a real ARIA grid (role="grid"), like Table, built on react-aria-components' Virtualizer instead of Table's own hooks — only the rows scrolled into view are ever mounted, so a dataset with thousands of rows costs the same to render as one with a dozen. That windowing is also why the underlying markup is <div>s carrying grid/row/gridcell roles rather than a real <table>: native table layout can't support mounting and unmounting rows as the user scrolls.

Composing it mirrors Table — DataGridHeader/DataGridColumn/DataGridBody/DataGridRow/ DataGridCell are read as data to build the grid's collection, not rendered as literal markup. rowHeight is required: the virtualizer needs a height up front to compute scroll position and total size without measuring every row first. Pass a fixed pixel number so every row renders at that height, or "auto" (paired with estimatedRowHeight) to measure each row from its own content — see Variable row height. Give the grid itself a bounded height (directly, or via a className override) so its scroll viewport actually activates — a grid tall enough to show every row scrolls nowhere.

Name
JSX
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell
} from '@chassis-ui/react'

const rows = Array.from({ length: 200 }, (_, i) => ({
  id: i,
  name: `User ${i}`,
  role: ['Engineer', 'Designer', 'Product'][i % 3]
}))

export const Example = () => (
  <DataGrid aria-label="Users" rowHeight={40}>
    <DataGridHeader>
      <DataGridColumn isRowHeader>Name</DataGridColumn>
      <DataGridColumn>Role</DataGridColumn>
    </DataGridHeader>
    <DataGridBody items={rows}>
      {(row) => (
        <DataGridRow id={row.id}>
          <DataGridCell>{row.name}</DataGridCell>
          <DataGridCell>{row.role}</DataGridCell>
        </DataGridRow>
      )}
    </DataGridBody>
  </DataGrid>
)

Sorting

Add allowsSorting to a DataGridColumn to make it clickable (and keyboard-activatable) — the same contract as Table. DataGrid doesn't sort the data itself; it reports the requested column/direction via onSortChange, so pair it with sortDescriptor and sort the array in that handler.

Name
JSX
import { useMemo, useState } from 'react'
import type { SortDescriptor } from 'react-stately'
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell
} from '@chassis-ui/react'

const rows = [
  { id: 1, name: 'Mark Otto', role: 'Engineer' },
  { id: 2, name: 'Jacob Thornton', role: 'Designer' },
  { id: 3, name: 'Larry Bird', role: 'Engineer' },
  { id: 4, name: 'Ashley Grant', role: 'Product' }
]

export const Example = () => {
  const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
    column: 'name',
    direction: 'ascending'
  })

  const sortedRows = useMemo(() => {
    const key = sortDescriptor.column as keyof (typeof rows)[number]
    const sorted = [...rows].sort((a, b) => (a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0))
    return sortDescriptor.direction === 'descending' ? sorted.reverse() : sorted
  }, [sortDescriptor])

  return (
    <DataGrid
      aria-label="Team"
      onSortChange={setSortDescriptor}
      rowHeight={40}
      sortDescriptor={sortDescriptor}
    >
      <DataGridHeader>
        <DataGridColumn allowsSorting id="name" isRowHeader>
          Name
        </DataGridColumn>
        <DataGridColumn allowsSorting id="role">
          Role
        </DataGridColumn>
      </DataGridHeader>
      <DataGridBody items={sortedRows}>
        {(row) => (
          <DataGridRow id={row.id}>
            <DataGridCell>{row.name}</DataGridCell>
            <DataGridCell>{row.role}</DataGridCell>
          </DataGridRow>
        )}
      </DataGridBody>
    </DataGrid>
  )
}

Selection

Set selectionMode="multiple" or selectionMode="single" and control it with selectedKeys/onSelectionChange, same as Table. Unlike Table, the selection checkboxes themselves aren't automatic — place a DataGridSelectAllCell inside a DataGridColumn for the header, and a DataGridSelectionCell inside a DataGridCell for each row. Neither takes a row key: each reads the selection state react-aria-components already publishes for the row it's rendered in. Both render a native checkbox wired to that state, styled the same as Table's, and labelled by their row's row-header cells.

Name
JSX
import { useState } from 'react'
import type { Selection } from 'react-stately'
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell,
  DataGridSelectAllCell,
  DataGridSelectionCell
} from '@chassis-ui/react'

const rows = [
  { id: 1, name: 'Mark Otto', role: 'Engineer' },
  { id: 2, name: 'Jacob Thornton', role: 'Designer' },
  { id: 3, name: 'Larry Bird', role: 'Engineer' }
]

export const Example = () => {
  const [selectedKeys, setSelectedKeys] = useState<Selection>(new Set())

  return (
    <DataGrid
      aria-label="Team"
      onSelectionChange={setSelectedKeys}
      rowHeight={40}
      selectedKeys={selectedKeys}
      selectionMode="multiple"
    >
      <DataGridHeader>
        <DataGridColumn className="datagrid-selection-cell" defaultWidth={44} minWidth={44}>
          <DataGridSelectAllCell />
        </DataGridColumn>
        <DataGridColumn isRowHeader>Name</DataGridColumn>
        <DataGridColumn>Role</DataGridColumn>
      </DataGridHeader>
      <DataGridBody items={rows}>
        {(row) => (
          <DataGridRow id={row.id}>
            <DataGridCell className="datagrid-selection-cell">
              <DataGridSelectionCell />
            </DataGridCell>
            <DataGridCell>{row.name}</DataGridCell>
            <DataGridCell>{row.role}</DataGridCell>
          </DataGridRow>
        )}
      </DataGridBody>
    </DataGrid>
  )
}

Column widths

Unlike Table, whose columns size themselves the way any native <table> does, DataGrid's virtualized layout computes every column's width itself, splitting the grid evenly across columns by default — a width/className rule on a cell has no effect here. Give a DataGridColumn defaultWidth/minWidth/maxWidth to size it explicitly, e.g. a fixed pixel width for a narrow selection/icon column (as in the Selection example above) or an '<n>fr' value to weight it against the grid's other columns.

Variable row height

Pass rowHeight="auto" with a required estimatedRowHeight to size each row from its own rendered content instead of a single fixed height shared by every row. estimatedRowHeight seeds the virtualizer's scroll-position math before a row has been measured; a row's real height can end up taller or shorter than that estimate once it renders, which can cause a visible scroll-jump for rows the viewport hasn't reached yet. Prefer a fixed rowHeight unless rows genuinely vary — e.g. wrapped text of unpredictable length, as below.

Name
JSX
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell
} from '@chassis-ui/react'

const rows = [
  {
    id: 1,
    name: 'Mark Otto',
    bio: 'Co-founder, focused on design systems and component APIs.'
  },
  {
    id: 2,
    name: 'Jacob Thornton',
    bio: 'Co-founder.'
  },
  {
    id: 3,
    name: 'Larry Bird',
    bio: 'Handles onboarding docs and the getting-started guide — writes most of the long-form tutorial content, keeps the changelog current, and reviews every doc PR before it merges.'
  }
]

export const Example = () => (
  <DataGrid aria-label="Team" bordered estimatedRowHeight={48} rowHeight="auto">
    <DataGridHeader>
      <DataGridColumn defaultWidth={160} isRowHeader>
        Name
      </DataGridColumn>
      <DataGridColumn>Bio</DataGridColumn>
    </DataGridHeader>
    <DataGridBody items={rows}>
      {(row) => (
        <DataGridRow id={row.id}>
          <DataGridCell>{row.name}</DataGridCell>
          <DataGridCell>{row.bio}</DataGridCell>
        </DataGridRow>
      )}
    </DataGridBody>
  </DataGrid>
)

Pinned columns

Set pin="start" or pin="end" on a DataGridColumn to keep it visible while the grid scrolls horizontally — start pins it to the leading edge, end to the trailing edge. Multiple pinned columns on the same side stack in declaration order, so the first pin="start" column sits at the very edge and each following one sits just past the previous. Pin columns at the true start or end of the column list — a pinned column declared in the middle of the set isn't a supported arrangement.

Name
Status
JSX
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell
} from '@chassis-ui/react'

const rows = [
  {
    id: 1,
    name: 'Mark Otto',
    bio: 'Co-founder, focused on design systems and component APIs.',
    notes: 'Prefers async review over live meetings.',
    location: 'Boston, MA',
    role: 'Engineer',
    status: 'Active'
  },
  {
    id: 2,
    name: 'Jacob Thornton',
    bio: 'Co-founder, works across the build pipeline and tooling.',
    notes: 'Owns the release process.',
    location: 'San Francisco, CA',
    role: 'Engineer',
    status: 'Active'
  },
  {
    id: 3,
    name: 'Larry Bird',
    bio: 'Handles onboarding docs and the getting-started guide.',
    notes: 'Out most Fridays.',
    location: 'Springfield, IL',
    role: 'Writer',
    status: 'Inactive'
  }
]

export const Example = () => (
  <DataGrid aria-label="Team" bordered rowHeight={44}>
    <DataGridHeader>
      <DataGridColumn defaultWidth={160} isRowHeader pin="start">
        Name
      </DataGridColumn>
      <DataGridColumn defaultWidth={280}>Bio</DataGridColumn>
      <DataGridColumn defaultWidth={220}>Notes</DataGridColumn>
      <DataGridColumn defaultWidth={200}>Location</DataGridColumn>
      <DataGridColumn defaultWidth={120}>Role</DataGridColumn>
      <DataGridColumn defaultWidth={100} pin="end">
        Status
      </DataGridColumn>
    </DataGridHeader>
    <DataGridBody items={rows}>
      {(row) => (
        <DataGridRow id={row.id}>
          <DataGridCell>{row.name}</DataGridCell>
          <DataGridCell>{row.bio}</DataGridCell>
          <DataGridCell>{row.notes}</DataGridCell>
          <DataGridCell>{row.location}</DataGridCell>
          <DataGridCell>{row.role}</DataGridCell>
          <DataGridCell>{row.status}</DataGridCell>
        </DataGridRow>
      )}
    </DataGridBody>
  </DataGrid>
)

Async loading

Pass onLoadMore to DataGridBody to fetch and append more rows as the grid scrolls near its last one — useful for a dataset too lg to load up front. It's only available on the items/render-function form of children, and the props are typed so that's enforced: the loading row is generated by appending to items and rendering it through that same function, so there's nothing for it to do alongside a hand-written list of DataGridRow elements. Pair it with isLoading (set while the fetch is in flight) and loadingContent (the affordance shown in its place, e.g. a spinner) — onLoadMore isn't called again while isLoading is true, so a fetch already running doesn't get triggered a second time before it resolves. Stop passing onLoadMore once there's nothing left to load (e.g. the fetched page came back short of a full page) to remove the loading row entirely.

Name
JSX
import { useState } from 'react'
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell
} from '@chassis-ui/react'

interface Person {
  id: number
  name: string
  role: string
}

const PAGE_SIZE = 20
const TOTAL = 200
const allPeople: Person[] = Array.from({ length: TOTAL }, (_, id) => ({
  id,
  name: `Person ${id}`,
  role: ['Engineer', 'Designer', 'Manager'][id % 3]
}))

// Stands in for a real paginated API call — replace with an actual fetch of the next page.
const fetchPeoplePage = (page: number): Promise<Person[]> =>
  new Promise((resolve) => {
    setTimeout(() => resolve(allPeople.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE)), 800)
  })

export const Example = () => {
  const [people, setPeople] = useState<Person[]>([])
  const [page, setPage] = useState(0)
  const [isLoading, setIsLoading] = useState(false)

  const onLoadMore = () => {
    setIsLoading(true)
    fetchPeoplePage(page).then((nextPage) => {
      setPeople((current) => [...current, ...nextPage])
      setPage((current) => current + 1)
      setIsLoading(false)
    })
  }

  const hasMore = people.length < TOTAL

  return (
    <DataGrid aria-label="People" rowHeight={40}>
      <DataGridHeader>
        <DataGridColumn isRowHeader>Name</DataGridColumn>
        <DataGridColumn>Role</DataGridColumn>
      </DataGridHeader>
      <DataGridBody
        isLoading={isLoading}
        items={people}
        loadingContent="Loading more…"
        onLoadMore={hasMore ? onLoadMore : undefined}
      >
        {(person) => (
          <DataGridRow id={person.id}>
            <DataGridCell>{person.name}</DataGridCell>
            <DataGridCell>{person.role}</DataGridCell>
          </DataGridRow>
        )}
      </DataGridBody>
    </DataGrid>
  )
}

The header row stays pinned to the top of the grid's scrollable area as body rows scroll underneath it — no extra setup required. Pass footer for content pinned below the body, e.g. a totals row or a "load more" control — like Table's footer prop, it renders as plain markup outside the grid's own keyboard-navigable row/cell structure, and (unlike the header) it isn't part of the scrollable region at all, so it never scrolls out of view along with the body rows.

Name
JSX
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell
} from '@chassis-ui/react'

const rows = Array.from({ length: 200 }, (_, i) => ({
  id: i,
  name: `User ${i}`,
  role: ['Engineer', 'Designer', 'Product'][i % 3]
}))

export const Example = () => (
  <DataGrid aria-label="Users" bordered footer={`${rows.length} users total`} rowHeight={40}>
    <DataGridHeader>
      <DataGridColumn isRowHeader>Name</DataGridColumn>
      <DataGridColumn>Role</DataGridColumn>
    </DataGridHeader>
    <DataGridBody items={rows}>
      {(row) => (
        <DataGridRow id={row.id}>
          <DataGridCell>{row.name}</DataGridCell>
          <DataGridCell>{row.role}</DataGridCell>
        </DataGridRow>
      )}
    </DataGridBody>
  </DataGrid>
)

Keyboard navigation

Once a cell has focus, arrow keys move focus across the grid, the same as Table — no extra setup required.

Variants

align, bordered, borderless, hover, sm, and color all apply to the grid's root element, the same as Table's equivalent props. color also colors the footer, which is outside that element.

Name
JSX
import {
  DataGrid,
  DataGridHeader,
  DataGridColumn,
  DataGridBody,
  DataGridRow,
  DataGridCell
} from '@chassis-ui/react'

const rows = [
  { id: 1, name: 'Mark Otto', role: 'Engineer' },
  { id: 2, name: 'Jacob Thornton', role: 'Designer' },
  { id: 3, name: 'Larry Bird', role: 'Engineer' }
]

export const Example = () => (
  <DataGrid aria-label="Team" bordered hover rowHeight={40} sm>
    <DataGridHeader>
      <DataGridColumn isRowHeader>Name</DataGridColumn>
      <DataGridColumn>Role</DataGridColumn>
    </DataGridHeader>
    <DataGridBody items={rows}>
      {(row) => (
        <DataGridRow id={row.id}>
          <DataGridCell>{row.name}</DataGridCell>
          <DataGridCell>{row.role}</DataGridCell>
        </DataGridRow>
      )}
    </DataGridBody>
  </DataGrid>
)

Scope

  • Variable row height re-measures per row, not per column. rowHeight="auto" (see Variable row height) sizes each row independently, but a column's width is still fixed up front — a cell's content wrapping to more lines only grows that one row, it doesn't reflow neighboring columns.
  • The header row stays a fixed height in rowHeight="auto" mode, pinned to estimatedRowHeight rather than measured — only body rows are. A column header whose content needs more room than that visually overflows rather than growing the header.
  • The loader row's underlying aria-level attribute is invalid on a role="grid" row (it's only meaningful on a treegrid row). This comes from react-aria-components's own TableLoadMoreItem implementation, not from anything DataGrid adds — every other row's markup is unaffected.
  • No stacked variant. Table's stacked prop collapses rows into label/value blocks below a container width, using container queries to detect the switch — that check can't see how many rows the virtualizer has mounted, so a row's true height would no longer match rowHeight once stacked, breaking the scroll math. Tables with too many columns for a narrow viewport are better served by Table's own stacked/responsive props, which don't have this constraint.
  • No zebra striping. CSS-only striping (:nth-of-type) counts a row's position among currently-mounted siblings, not its logical position in the dataset — the pattern would visibly shift as the virtualizer's mounted window changes during scroll.
  • No interactive column resizing or reordering, no nested/expandable rows. react-aria-components supports these on Table, but they're not wired up here — columns can still be given a fixed size up front (see Column widths), just not resized by the user at runtime.
  • footer doesn't pick up an instance-scoped color/border override. It renders outside the grid's own scrollable element (see Header & footer pinning), so it can't inherit CSS custom properties set directly on that specific DataGrid instance's own class — only a global --table-* token override reaches it. This matches every other DataGrid instance on the page, just not one re-themed individually. The color prop is not such an override: the component gives the footer the same color classes as the grid.
  • Columns are already windowed horizontally — no extra work needed for wide grids. The underlying react-aria-components/react-stately layout engine only mounts DOM for cells that intersect the horizontal viewport (the same visible-range mechanism that windows rows vertically), confirmed by rendering an 80-column grid and finding only 11 columnheader elements in the DOM regardless of total column count. Everything that has to find a specific column's cells in the DOM — pinned-column positioning, the scroll cues, fr-column measurement — therefore matches them on their aria-colindex (which the layout engine sets from the column's position in the collection) rather than counting DOM children, whose number is the size of the mounted window. One caveat: the layout engine's own per-row cell-building pass isn't skipped for columns already scrolled past on the left (only columns past the right edge of the viewport are skipped) — the cost of computing a row's cell offsets scales with column count up to the visible window, not just the visible window's size. This is a layout-computation cost, not a DOM-rendering one, and only matters at very high column counts (100+).
  • No id prop, unlike Table. react-aria-components' Table doesn't accept one: it generates the grid's own id and derives every cell's and column header's id from it (which is what the row/checkbox aria-labelledby wiring points at), so an overridden one would break those references. Use aria-labelledby to point at a visible heading, or aria-label, rather than labelling via an id of your own.

API

DataGrid

PropTypeDefault
align?"bottom" | "middle" | "top"—
Set the vertical alignment of cell content. Mirrors Table's prop of the same name for API parity — same as Table, this awaits chassis-css adding the matching .align-* styles.
aria-label?string—
An accessible label for the grid, used when there's no visible heading.
aria-labelledby?string—
Identifies a visible heading element for the grid.
bordered?boolean—
Add borders on all sides of the grid and cells.
borderless?boolean—
Remove borders on all sides of the grid and cells.
children[ReactElement<DataGridHeaderProps<T>, string | JSXElementConstructor<any>>, ReactElement<DataGridBodyProps<T>, string | JSXElementConstructor<...>>]—
A DataGridHeader and a DataGridBody, each built from DataGridColumn/DataGridRow/ DataGridCell.
className?string—
A string of all className you want applied to the component.
color?ContextColor—
Sets the color of the component.
disabledKeys?Iterable<Key>—
A list of row keys to disable. Disabled rows cannot be selected, focused, or interacted with.
estimatedRowHeight?number—
Seeds the virtualizer's scroll-position math for rows that haven't been measured yet. Required when rowHeight="auto" — pick a value close to the typical row's real height to minimize scroll-jump on first measurement. A row's real height can still turn out far from this estimate once it renders, which can cause a visible scroll-jump for rows the viewport hasn't reached yet.
footer?ReactNode—
Content shown below the grid, e.g. a totals row or a "load more" control. Rendered as plain markup outside the grid's own scrollable/virtualized region — not part of the keyboard-navigable grid, and never scrolls out of view along with the body rows. Mirrors Table's footer prop for API parity.
hover?boolean—
Enable a hover state on grid rows.
onSelectionChange?((keys: Selection) => void)—
Handler that is called when the selection changes.
onSortChange?((descriptor: SortDescriptor) => void)—
Handler that is called when a column is sorted.
ref?Ref<HTMLDivElement>—
rowHeightnumber | "auto"—
Row height in pixels, or "auto" to measure each row from its own rendered content instead of a single fixed height shared by every row (pair it with a required estimatedRowHeight, and see the docs site's "Variable row height" section for the tradeoffs). A fixed number renders every row, including the header, at that exact height; content taller than it visually overflows rather than growing the row.
selectedKeys?Selection—
The currently selected row keys (controlled).
selectionMode?"none" | "single" | "multiple"none
The type of selection that is allowed.
sm?boolean—
Make the grid more compact by cutting all cell padding.
sortDescriptor?SortDescriptor—
The current sort column and direction.

DataGridHeader

PropTypeDefault
childrenReactNode | ((column: T) => ReactElement<unknown, string | JSXElementConstructor<any>>)—
DataGridColumn elements, or a render function paired with columns for dynamic column generation.
className?string—
A string of all className you want applied to the header row group.
columns?Iterable<T>—
A list of column data objects, rendered via the function form of children.
dependencies?readonly unknown[]—
Values that should invalidate the column cache when using the columns/render-function form of children — see DataGridBody's dependencies for why this matters.

DataGridColumn

PropTypeDefault
allowsSorting?boolean—
Whether the column allows sorting. Adds a sort indicator and makes the header clickable/keyboard-activatable.
childrenReactNode—
Rendered contents of the column header.
className?string—
A string of all className you want applied to the column header.
defaultWidth?ColumnSize | null—
The initial width of the column, e.g. for a narrow selection/icon column — a plain number or '<n>%' for a fixed size, or '<n>fr' to share remaining space with other fractional columns in proportion (columns default to '1fr', so they split space evenly unless given one of these). Unlike Table, which sizes a narrow column via width: 1% relying on native <table> auto-layout, DataGrid's virtualized layout computes every column's width itself — a CSS width rule on the cell has no effect, so this prop is the only way to size a column.
id?Key—
The unique id of the column, referenced by sortDescriptor.column.
isRowHeader?boolean—
Whether this column is a row header, announced by assistive technology during row navigation.
maxWidth?ColumnStaticSize | null—
The maximum width of the column, as a fixed pixel number or '<n>%'.
minWidth?ColumnStaticSize | null—
The minimum width of the column, as a fixed pixel number or '<n>%'.
pin?"start" | "end"—
Pin the column so it stays visible while the grid scrolls horizontally: 'start' pins it to the leading edge, 'end' to the trailing edge. Stacks correctly with other pinned columns on the same side, in declaration order.
textValue?string—
A string representation of the column header, used for accessibility announcements. Defaults to children when it's a plain string — set this explicitly when the header contains anything else (an icon, a Tooltip, etc.).

DataGridBody

PropTypeDefault
childrenReactElement<unknown, string | JSXElementConstructor<any>> | ReactElement<unknown, string | JSXElementConstructor<any>>[] | ((item: T) => ReactElement<...>)—
DataGridRow elements. A render function called once per item in items, returning that row's DataGridRow.
className?string—
A string of all className you want applied to the body row group.
dependencies?readonly unknown[]—
Values that should invalidate the row cache when using the items/render-function form of children — e.g. a value from outside items that the render function reads. Without this, changing that outside value won't re-render already-cached rows, since dynamic rows are only rebuilt when items or dependencies change by reference, not on every parent re-render.
isLoading?boolean—
Whether more items are currently being fetched. Shows loadingContent in the loader row while true, and — until this goes back to false — suppresses further onLoadMore calls, so one scroll-into-view doesn't fire the callback again before the in-flight fetch resolves.
items?Iterable<T>—
A list of row data objects, rendered via the function form of children.
loadingContent?ReactNode—
Content rendered inside the loader row while isLoading is true, e.g. a spinner. Only takes effect alongside onLoadMore.
onLoadMore?(() => void)—
Called when the grid scrolls near its last row, so more data can be fetched and appended to items. Pair with isLoading so a fetch already in flight isn't triggered again before it resolves.
renderEmptyState?((props: TableBodyRenderProps) => ReactNode)—
Content shown in place of rows when items is empty.

DataGridRow

PropTypeDefault
childrenReactNode | ((column: T) => ReactElement<unknown, string | JSXElementConstructor<any>>)—
DataGridCell elements, or a render function called once per column with that column's data — required when the row's parent DataGridBody uses the items/render-function form.
className?string—
A string of all className you want applied to the row.
columns?Iterable<T>—
A list of column data objects, rendered via the function form of children.
id?Key—
The unique id of the row, referenced by selectedKeys/disabledKeys.
textValue?string—
A string representation of the row's contents, used for typeahead.

DataGridCell

PropTypeDefault
childrenReactNode—
The contents of the cell.
className?string—
A string of all className you want applied to the cell.
colSpan?number—
Indicates how many columns the cell spans.
id?Key—
The unique id of the cell.
textValue?string—
A string representation of the cell's contents, used for typeahead.

DataGridSelectionCell

PropTypeDefault
className?string—
A string of all className you want applied to the checkbox, replacing the default check-input.

DataGridSelectAllCell takes no props — it reads the grid's selection state directly.