DataGrid API - API
General Props 250
Callback Props 41
Styling Props 31
Methods 36

General Props

Below you can find a list of public props that the <ReactDataGrid /> supports. Besides this list, the component also supports all standard DOM attributes - those are not explicitly mentioned here, with a few exceptions.

Bool
default: true

If true, will make the first row of the <ReactDataGrid /> active when the <ReactDataGrid /> receives focus - see activeIndex.
When the <ReactDataGrid /> receives focus and you hit the ArrowDown key, the first row is becomes active, even if activateRowOnFocus is false.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import TextInput from '../components/TextInput'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1,
    header: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
];

const App = () => {
  const [activateRowOnFocus, setActivateRowOnFocus] = useState(true);

  return (
    <div>
      <p>Navigate with Tab key</p>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={activateRowOnFocus}
          onChange={setActivateRowOnFocus}
        >
          Activate row on focus
        </CheckBox>
      </div>

      <TextInput style={{ marginBottom: 20, padding: 5, width: 250 }} type="text" autoFocus defaultValue="Hit tab to navigate to grid" />
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        activateRowOnFocus={activateRowOnFocus}
        columns={columns}
        dataSource={people}
      />
      <TextInput style={{ marginTop: 20, padding: 5, width: 250 }} type="text" defaultValue="Hit shift+tab to navigate to grid" />
    </div>
  );
}

export default () => <App />

Number[2]
default: undefined

This enables cell keyboard navigation in the <ReactDataGrid /> (as opposed to row keyboard navigation). For row navigation, see activeIndex or defaultActiveIndex.
This is a controlled prop. For the uncontrolled version, see defaultActiveCell.
When the user uses the keyboard to change the currently active<ReactDataGrid /> cell, make sure you update the value of the controlled activeCell prop when onActiveCellChange is triggered.
The value of the activeCell should be an array of length 2, the first value being the row index, while the second value is the column index of the activeCell.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 300 }
const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', minWidth: 100, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
]

const App = () => {
  const [enableKeyboardNavigation, setEnableKeyboardNavigation] = useState(true);
  const [activeCell, setActiveCell] = useState([4, 1]);

  return (
    <div>
      <div>
        <CheckBox checked={enableKeyboardNavigation} onChange={setEnableKeyboardNavigation}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <p>Currently active cell: {JSON.stringify(activeCell)}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        activeCell={activeCell}
        onActiveCellChange={setActiveCell}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: 100

When keyboard navigation is used (arrow up/down/left/right) to change the activeCell, the keyboard events can fire very quickly, which would be a bottleneck to update the <ReactDataGrid /> active cell so often. Therefore, the updates are throttled, at 100 milliseconds by default in order to keep the <ReactDataGrid /> snappy & responsive.
The value specifies the number of milliseconds to throttle the update by.
For updating active row, see the activeIndexThrottle prop.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 300 }
const defaultActiveCell = [4, 1]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', minWidth: 120, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', hedaer: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        activeCellThrottle={300}
        defaultActiveCell={defaultActiveCell}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

When keyboard navigation is enabled, this controls which row is active.
This is a controlled prop. For the uncontrolled version, see defaultActiveIndex.
When the active index changes, onActiveIndexChange(activeIndex) is called, so you need to update the value of activeIndex manually, since this is a controlled prop.
When navigating the <ReactDataGrid /> with keyboard navigation, as the active index is updated, the <ReactDataGrid /> is automatically scrolled to show the currently active index in the viewport.
When using the controlled activeIndex prop and onActiveIndexChange callback prop to update the activeIndex, if you're doing other compute intensive stuff on the render function, you might notice some performance degradation in the scenario when the user keeps arrow up/down key pressed to quickly navigate to other records. If this is the case, it's better to use the uncontrolled defaultActiveIndex prop instead to obtain better performance.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 300 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', minWidth: 100, defaultFlex: 1, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
]

const App = () => {
  const [enableKeyboardNavigation, setEnableKeyboardNavigation] = useState(true);
  const [activeIndex, setActiveIndex] = useState(2);

  return (
    <div>
      <div>
        <CheckBox checked={enableKeyboardNavigation} onChange={setEnableKeyboardNavigation}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <p>Current active index: {activeIndex}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        activeIndex={activeIndex}
        onActiveIndexChange={setActiveIndex}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: 0

When keyboard navigation is used (arrow up/down) to change the active row index (see activeIndex), the keyboard events can fire very quickly, which would be a bottleneck to update the <ReactDataGrid /> active cell so often. Therefore, the updates are throttled, at 100 milliseconds by default in order to keep the <ReactDataGrid /> snappy & responsive.
The value specifies the number of milliseconds to throttle the update by.
For updating active cell, see the activeCellThrottle prop.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 300 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  const [activeIndex, setActiveIndex] = useState(1);

  return (
    <div>
      <p>Active index: {activeIndex}</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        activeIndexThrottle={300}
        activeIndex={activeIndex}
        onActiveIndexChange={setActiveIndex}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

bool
default: true

Specifies whether groups can be split when reordering columns. Defaults to false, so groups can be split by default. Specify false if you don't want to allow groups to be split.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, hedaer: 'Id', defaultVisible: false },
  { name: 'firstName', group: 'personalInfo', defaultFlex: 1, header: 'First Name' },
  { name: 'age', group: 'personalInfo', type: 'number', header: 'Age' },
  { name: 'email', group: 'contactInfo', defaultFlex: 1, header: 'Email' },
  { name: 'phone', group: 'contactInfo', header: 'Phone'  },
  { name: 'city', group: 'location', header: 'City' },
  { name: 'streetName', group: 'street', defaultFlex: 1, header: 'Street name' },
  { name: 'streetNo', group: 'street', type: 'number', header: 'Street no' }
]
const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', header: 'Personal info' },
  { name: 'contactInfo', header: 'Contact info' },
  { name: 'location', header: 'Location' }
]

const dataSource = [
  { id: 0, firstName: 'Bob', age: 25, email: 'bobby@whocares.com', phone: '+7403 456 768', city: 'Paris', streetName: 'Champs Elysee', streetNo: 34 },
  { id: 1, firstName: 'Lynda', age: 38, email: 'lynda@idont.com', phone: '+7103 66 98 768', city: 'London', streetName: 'St Mary', streetNo: 14 },
  { id: 2, firstName: 'Richard', age: 18, email: 'richy@rich.com', phone: '+173 668 08 83', city: 'Manchester', streetName: 'St Robert', streetNo: 53 },
  { id: 3, firstName: 'Michael', age: 45, email: 'mike@mikey.com', phone: '+075 0628 156 74', city: 'Los Angeles', streetName: 'Greenfield', streetNo: 24 },
  { id: 4, firstName: 'Martin', age: 12, email: 'martin@bobson.com', phone: '+173 5624 675 462', city: 'San Jose', streetName: 'Patrick Ball', streetNo: 67 }
]
const gridStyle = { minHeight: 500 }

const App = () => {
  const [allowGroupSplitOnReorder, setAllowGroupSplitOnReorder] = useState(false)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <p>Try dragging columns to break up some groups.</p>
        <CheckBox checked={allowGroupSplitOnReorder} onChange={setAllowGroupSplitOnReorder}>
          Allow group split on reorder
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnMinWidth={100}
        columns={columns}
        groups={groups}
        allowGroupSplitOnReorder={allowGroupSplitOnReorder}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Specifies if a third, unsorted state should be allowed within a single sort <ReactDataGrid />, when toggling the sort.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [sortable, setSortable] = useState(true)
  const [allowUnsort, setAllowUnsort] = useState(true)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={sortable}
          onChange={setSortable}
        >
          Sortable grid
        </CheckBox>
      </div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          disabled={!sortable}
          checked={allowUnsort}
          onChange={setAllowUnsort}
        >
          Allow unsorted state
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        sortable={sortable}
        allowUnsort={allowUnsort}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

When this is specified as true, after an edit is complete, the grid will automatically receive focus.
If set to false, the grid will not request focus after an edit is complete.
Also see onEditComplete related prop.

Bool
default: true

When this is specified as true, after an edit is canceled, the grid will automatically receive focus.
If set to false, the grid will not request focus after an edit is canceled.
Also see onEditCancel related prop.

Object
default: undefined

Specifies a value for cell selection. This is a controlled prop. For the uncontrolled version, see defaultCellSelection.
The cell selection value is an object with keys being strings - each string representing a cell. Values should be the boolean true. The string for each cell is the value of the idProperty for that row, followed by a comma and by the name/id of corresponding column: <idProperty value>,<column id or name>: eg "id1,firstName".
Specifying this prop enables cell selection.
By default cell selection is multiple. If you want to enable single cell selection, specify multiSelect=false.
You can use the little square at the bottom-right border of the active cell to drag and extend the current cell selection.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, resizable: false },
  { name: 'name', header: 'Name', defaultFlex: 1, sortable: false },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultWidth: 100, type: 'number' }
]

const App = () => {
  const [cellSelection, setCellSelection] = useState({"2,name": true, "2,city": true})

  return (
    <div>
      <p>
        Selected cells: {cellSelection.length == 0 ? 'none' : JSON.stringify(cellSelection)}.
      </p>
      <ReactDataGrid
        idProperty="id"
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool|Object
default: undefined

Specifying a truthy value, will show a checkbox column as the first column of the <ReactDataGrid />. When checkboxColumn=true, the checkbox column with the default configuration will be displayed. However, you can use an object as the value for this prop, so you can configure any column properties just like for a normal <ReactDataGrid /> column.
The checkbox selection column is usually used together with selected (or the uncontrolled defaultSelected) , unselected (or the uncontrolled defaultUnselected) and onSelectionChange.
unselected (or the uncontrolled defaultUnselected) only needs to be used when the <ReactDataGrid /> is configured with a remote dataSource.
By default, clicking on a row changes the row selection. You can use checkboxOnlyRowSelect=true to only update row selection when the user interacts with the checkboxes (so, it won't update when the row is clicked anywhere else).
You can use checkboxColumn.checkboxTabIndex in order to assign a tabIndex to the checkboxes in the column in order for the checkboxes to be reachable with tab-navigation.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 400, marginTop: 10 }

const defaultSelected = { 1: true, 3: true }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const loadData = ({ skip, limit, sortInfo }) => {
  return fetch(DATASET_URL+ '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo): '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [checkboxOnlyRowSelect, setCheckboxOnlyRowSelect] = useState(true);
  const [checkboxColumn, setCheckboxColumn] = useState(true);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={checkboxColumn} onChange={setCheckboxColumn}>
          Checkbox column
        </CheckBox>
      </div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={checkboxOnlyRowSelect}
          onChange={setCheckboxOnlyRowSelect}
        >
          Update row select using checkbox clicks only
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        key={'grid-' + checkboxOnlyRowSelect}
        style={gridStyle}
        checkboxColumn={checkboxColumn}
        columns={columns}
        checkboxOnlyRowSelect={checkboxOnlyRowSelect}
        pagination
        defaultSelected={defaultSelected}
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Number
default: null

You can use checkboxColumn.checkboxTabIndex in order to assign a tabIndex to the checkboxes in the column in order for the checkboxes to be reachable with tab-navigation. The default value is null, so column checkboxes do not participate in tab-navigation.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 400, marginTop: 10 }

const defaultSelected = {}

const columns = [
  { name: 'id', type: 'number', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const loadData = ({ skip, limit, sortInfo }) => {
  return fetch(DATASET_URL+ '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo): '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [checkboxTabIndex, setCheckboxTabIndex] = useState(false);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={checkboxTabIndex}
          onChange={setCheckboxTabIndex}
        >
          Use tabIndex for checkboxes - so they can be reached with tab-navigation
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn={{
          checkboxTabIndex: checkboxTabIndex ? 0 : null
        }}
        columns={columns}
        pagination
        defaultSelected={defaultSelected}
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

If this prop is true, row selection is only performed/updated when the user interacts with the selection checkboxes (see checkboxColumn).
If this prop is false, clicking anywhere on <ReactDataGrid /> rows update the row selection.
This prop should be used in combination with checkboxColumn=true.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import Button from '@inovua/reactdatagrid-community/packages/Button'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 400, marginTop: 10 }

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  const [checkboxOnlyRowSelect, setCheckboxOnlyRowSelect] = useState(false);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={checkboxOnlyRowSelect}
          onChange={setCheckboxOnlyRowSelect}
        >
          Update row select using checkbox clicks only
        </CheckBox>
      </div>
      <ReactDataGrid
        key={'grid-' + checkboxOnlyRowSelect}
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        checkboxOnlyRowSelect={checkboxOnlyRowSelect}
        columns={columns}
        defaultSelected={true}
        sortable={false}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

bool
default: true

When the dataSource prop is updated, if this property is true, any cached values set via setItemAt or setItemPropertyAt are cleared.

Bool
default: true

When this is true, when collapsing an async node, it also collapses all its children, at any level of nesting, since when you re-expand the node, you want to display fresh data.
Only available when loadNode is specified - not available when loadNodeOnce is used.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store (async node)',
        size: '4.5Mb',
        nodes: null
      },
      {
        id: 2,
        name: 'iMovie (async node)',
        size: '106Mb',
        nodes: null
      },
      {
        id: 3,
        name: 'IRecall (async node)',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const loadNode = ({ node, nodeProps }) => {
  return new Promise((resolve, reject) => {

    setTimeout(() => {
      if (nodeProps.depth >=4 ) {
        resolve([
          { id: 1, name: 'First child of ' + node.name },
          { id: 2, name: 'Second child of ' + node.name }
        ])
      }
      resolve([
        { id: 1, name: 'First child of ' + node.name, nodes: null },
        { id: 2, name: 'Second child of ' + node.name, nodes: null }
      ])
    }, 200)
  })
}

const defaultExpandedNodes = { 1: true, '1/1': true }

const App = () => {
  const [expandedNodes, setExpandedNodes] = useState(defaultExpandedNodes);
  const [collapseChildrenOnAsyncNodeCollapse, setCollapseChildrenOnAsyncNodeCollapse] = useState(true);

  const onExpandedNodesChange = useCallback(({ expandedNodes }) => {
    setExpandedNodes(expandedNodes)
  }, [])

  return (
    <div>
      <h3>TreeGrid with async nodes</h3>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={collapseChildrenOnAsyncNodeCollapse}
          onChange={setCollapseChildrenOnAsyncNodeCollapse}
        >
          Collapse children on async node collapse
        </CheckBox>
      </div>
      <ReactDataGrid
        treeColumn="name"
        loadNode={loadNode}
        collapseChildrenOnAsyncNodeCollapse={collapseChildrenOnAsyncNodeCollapse}
        onExpandedNodesChange={onExpandedNodesChange}
        expandedNodes={expandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />

      <p>
        Expanded nodes: {JSON.stringify(expandedNodes, null, 2)}
      </p>
    </div>
  );
}
export default () => <App />

Object | true
default: undefined

Specifies groups that should render as collapsed. This is a controlled prop. For the uncontrolled version, see defaultCollapsedGroups.
Should be used together with expandedGroups/defaultExpandedGroups
The keys of the object should be the "paths" to collapsed groups. For example, if records are first grouped by country, and "uk" is a country shared by many records, and then grouped by city, with "London" being the city value for many items, then "uk/London" (a concatenation of the two, separated by groupPathSeparator) is the key to be used in the collapsedGroups object in order to render "London" people as collapsed.
As mentioned, the concatenation is done by using groupPathSeparator.
If true, it means all groups are collapsed, except those specified by expandedGroups
Just one of expandedGroups and collapsedGroups should be true at any given time.
When the user interacts with the groups and expands/collapses a group, onGroupCollapseChange is triggered (whether controlled collapsedGroups or uncontrolled defaultCollapsedGroups is used).
When using the controlled collapsedGroups, make sure you update the collapsedGroups value when onGroupCollapseChange is triggered, but also expandedGroups
collapsedGroups and expandedGroups should be both either controlled or uncontrolled.
collapsedGroups=true means all groups are collapsed (except those explicitly specified by expandedGroups).
expandedGroups=true means all groups are expanded, except those explicitly specified in collapsedGroups
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultWidth: 140, header: 'Country' },
  { name: 'city', defaultWidth: 140, header: 'City' },
  { name: 'email', defaultWidth: 140, defaultFlex: 1, header: 'Email' }
]

const App = () => {
  const [groupBy, setGroupBy] = useState(['country','city'])
  const [collapsedGroups, setCollapsedGroups] = useState({ 'uk/London': true, 'usa': true })
  const [expandedGroups, setExpandedGroups] = useState(true)

  const onGroupCollapseChange = useCallback((collapsedGroups, expandedGroups) => {
    setCollapsedGroups(collapsedGroups)
    setExpandedGroups(expandedGroups)
  }, [])

  return (
    <div>
      <p>
        Collapsed groups: {JSON.stringify(Object.keys(collapsedGroups))}.
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        collapsedGroups={collapsedGroups}
        expandedGroups={expandedGroups}
        onGroupCollapseChange={onGroupCollapseChange}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

This property is only used when expandedRows=true!
Specifies which rows in the <ReactDataGrid /> should be rendered collapsed, when all other rows are expanded (expandedRows=true). This is a controlled prop. For the uncontrolled version, see defaultCollapsedRows
For row expand to be meaningful, you have to specify renderRowDetails in order to render the row details on expand.
The keys in this object should be the ids of the collapsed rows, while the value for each key should be true.
Use onExpandedRowsChange to be notified when the expanded/collapsed rows change.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const renderRowDetails = ({ data }) => {
  return <div style={{ padding: 20}}>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const App = () => {
  const [expandedRows, setExpandedRows] = useState(true);
  const [collapsedRows, setCollapsedRows] = useState({ 1: true, 2: true });

  const onExpandedRowsChange = useCallback(({ expandedRows, collapsedRows }) => {
    setExpandedRows(expandedRows);
    setCollapsedRows(collapsedRows);
  }, [])

  return (
    <div>
      <div>
        <Button onClick={() => setExpandedRows(true)} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => setExpandedRows({})}>
          Collapse all
        </Button>
      </div>
      <p>
        Expanded rows: {expandedRows == null ? 'none' : JSON.stringify(expandedRows, null, 2)}.
      </p>
      {expandedRows === true ?<p>
        Collapsed rows: {collapsedRows == null ? 'none' : JSON.stringify(collapsedRows, null, 2)}.
      </p> : null}
      <ReactDataGrid
        idProperty="id"
        expandedRows={expandedRows}
        collapsedRows={collapsedRows}
        onExpandedRowsChange={onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String|HTMLElement|Boolean|Fn
default: undefined

Specifies the region/bounding box/element to which the column context menu is constrained to. By default, the <ReactDataGrid /> constrains the column context menu to the <ReactDataGrid /> node.
The value of this prop can be a query selector string, an HTMLElement, the boolean true (in which case, it's constrained to document.documentElement), the result of a call to getBoundingClientRect or a function returning any of the mentioned types.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 300 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1,
    header: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
];

const App = () => {
  return (
    <div>
      <p>Column menu constrained to document.documentElement</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnContextMenuConstrainTo={true}
        columnContextMenuPosition={"fixed"}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

Specifies the css position value to be used for the column context menu. If nothing is specified, the menu will have position: absolute.
Can be used in combination with columnContextMenuConstrainTo to make the menu constrained to a different element - in which case, you should use "fixed" positioning.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 300 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1,
    header: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
];

const App = () => {
  return (
    <div>
      <p>Column menu constrained to document.documentElement</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnContextMenuConstrainTo={true}
        columnContextMenuPosition={"fixed"}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

Configures the default width for <ReactDataGrid /> columns. If a column specifies a defaultWidth, that value overrides columnDefaultWidth.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', header: 'Name' },
  { name: 'email', header: 'Email' },
  { name: 'country', header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City' },
  { name: 'age', header: 'Age', type: 'number' }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        All columns have a default width of 250px
      </div>
      <ReactDataGrid
        idProperty="id"
        columnDefaultWidth={250}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Controls whether native browser text selection is active in <ReactDataGrid />column headers. Since this prop defaults to false, browser text selection is disabled in headers. Set this to true to enable text selection in the <ReactDataGrid /> headers.
This can be overridden by columns.headerUserSelect, at column-level.
For configuring text-selection in the <ReactDataGrid /> cells, use columnUserSelect.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', header: 'Name - double click to test selection', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1 },
]

const App = () => {
  const [columnHeaderUserSelect, setColumnHeaderUserSelect] = useState(true);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={columnHeaderUserSelect}
          onChange={setColumnHeaderUserSelect}
        >
          Enable browser text selection in column headers
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnHeaderUserSelect={columnHeaderUserSelect}
        columns={columns}
        dataSource={people}
        sortable={false}
      />
    </div>
  );
}

export default () => <App />

Number
default: 50

Specifies the maximum width for all the <ReactDataGrid /> columns. If a column specifies a maxWidth, that value overrides columnMaxWidth.
resizable columns cannot be user-resized to have a bigger size, neither can flexible columns stretch more that the specified maximum width.
For minimum size restrictions, see columnMinWidth.
Overridden by columns.maxWidth.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 80 },
  { name: 'firstName', header: 'Name maxWidth 200', defaultFlex: 2 },
  {
    name: 'country',
    header: 'Country maxWidth 250',
    maxWidth: 250,
    defaultFlex: 3,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultFlex: 1 }
];

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnMaxWidth={200}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: 50

Specifies the minimum width for all the <ReactDataGrid /> columns. If a column specifies a minWidth, that value overrides columnMinWidth.
resizable columns cannot be user-resized to be smaller than the specified minimum size, neither can flexible columns shrink to be smaller than the specified min-width.
For maximum size restrictions, see columnMaxWidth.
Overridden by columns.minWidth.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', minWidth: 40, maxWidth: 40 },
  { name: 'firstName', header: 'Name default minWidth', minWidth: 200, defaultFlex: 1 },
  {
    name: 'country',
    header: 'Country default minWidth',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', header: 'Age default minWidth' }
];

const App = () => {
  return (
    <div>
      <p>Default column minWidth=150</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        columnMinWidth={150}
      />
    </div>
  );
}

export default () => <App />

String[]
default: undefined

Specifies controlled column ordering. It should be an array with column identifiers (column.name or column.id).
When the <ReactDataGrid /> is configured with reorderable columns, column order should be updated when dropping a column to a new position. Make sure you update the columnOrder value by using onColumnOrderChange(columnOrder) prop, which gives you the new column order.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 140, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', minWidth: 80, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' },
  { name: 'email', minWidth: 80, defaultFlex: 1, draggable: false, header: 'Email - not draggable' }
]

const App = () => {
  const [columnOrder, setColumnOrder] = useState(['id', 'name', 'age', 'city', 'email']);
  const [reorderColumns, setReorderColumns] = useState(true);

  return (
    <div>
      <div>
        <CheckBox checked={reorderColumns} onChange={setReorderColumns}>
          Enable column reordering
        </CheckBox>
      </div>
      <p>Current column order: {JSON.stringify(columnOrder)}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        reorderColumns={reorderColumns}
        columnOrder={columnOrder}
        onColumnOrderChange={setColumnOrder}
        columns={columns}
        dataSource={people}
        sortable={false}
      />
    </div>
  );
}

export default () => <App />

Number
default: 20

Specifies the amount by which to scroll the grid horizontally when column reordering is perfomed. On each mousemove, the grid is scrolled horizontally by this amount
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultFlex: 1 },
  { name: 'firstName', header: 'Name', defaultWidth: 280 },
  { name: 'email', header: 'Email', defaultWidth: 280 },
  { name: 'country', header: 'Country', defaultWidth: 280,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultWidth: 280 },
  { name: 'age', header: 'Age', defaultWidth: 280 }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Try to reorder columns when there is a horizontal scrollbars - the grid will scroll horizontally very slow, since columnReorderScrollByAmount is configured to be 5 in this example.
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        columnReorderScrollByAmount={5}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object[]
default: undefined

An array of columns for the <ReactDataGrid />.
Below is a list with the most important properties each column object can have (they are also documented separately). The list is not exhaustive - the complete list is documented in this page, each supported prop is documented separately.
  • name - a column name. Will match a property from the items in the dataSource.
  • id - if the column doesn't have a name it needs to have a unique id.
  • header - will be displayed in the column header. Can be any valid React.Node or a function. If not present, column.name will be used (after it's upper-cased and humanized) as the column header.
  • render - a render function in order to perform custom rendering.
  • textAlign - a value for aligning column cell contents. If column.headerAlign is undefined, the column.textAlign will also be used for header alignment.
  • headerAlign - a value for aligning column header contents.
In order to boost performance of the <ReactDataGrid />, we treat props as immutable and only update the <ReactDataGrid /> when you pass different props.
In order to improve the rendering performance, make sure you pass the same reference to the columns array when rendering the <ReactDataGrid />, instead of building the columns array in the render function of your app and passing it new each time to the <ReactDataGrid />.
Passing a different instance of the columns at each render will slow down the rendering performance of the <ReactDataGrid />.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultWidth: 100,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    defaultFlex: 2,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object|Fn(cellProps): Object
default: undefined

Can be used as a render hook for cell contents (when specified as a function).
When not used as a function, use an object with DOM props to be applied to all cells in a specific column. It can contain any valid DOM properties, like className, style or onClick.
If you need to apply those props conditionally, you can use specify a function as the value for cellDOMProps and return an object with DOM props that will get applied on the rendered <div />.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const countryStyle = {
  color: '#7986cb'
}
const redColor = {
  color: '#ef9a9a'
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', defaultFlex: 1, minWidth: 100, header: 'Name', cellDOMProps: { style : redColor } },
  { name: 'country', cellDOMProps: (cellProps) => ({ style: countryStyle }), defaultFlex: 1, minWidth: 100, header: 'Country' },
  { name: 'city', defaultFlex: 1, minWidth: 100, header: 'City' },
  { name: 'age', minWidth: 150, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, value, rowIndex, column, dataSourceArray })
default: undefined

Configures the colspan for cells in the current column.
Please keep in mind that the grid has sorting/filtering/etc, so the same cells are not always siblings, as they can be sorted or filtered out or columns can be hidden or reordered.
Because of this, in the column.colspanand column.rowspan functions you have access to the data you need to make those truly dynamic.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    defaultWidth: 50,
    type: 'number',

  },
  {
    name: 'name',
    defaultFlex: 1,
    header: 'Name',
    colspan: ({ data, column, columns }) => {
      // make every other row cell expand for 2 columns if the next column is the age column
      if (data.id % 2 && columns[column.computedVisibleIndex] && columns[column.computedVisibleIndex + 1].name === 'age') {
        return 2
      }

      return 1
    }
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1
  },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <h3>Colspan example</h3>
      <ReactDataGrid
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

Specifies the flex amount for the column.
This is an uncontrolled property. For the controlled version, see column.flex.
It works similarly to browser flex-box: substracts the total fixed column widths from the total available space, then divides this by the sum of all flexes and multiplies that value with the flex value of each flexible column.
Additionally, column.minWidth and column.maxWidth can be configured for both fixed and flexible columns in order to ensure some minimum or maximum dimensions are always respected.
For the controlled version, see related column.flex
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 70 },
  { name: 'firstName', header: 'First Name', defaultFlex: 3 },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 2,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultFlex: 1 }
]

const App = () => {
  return (
    <div>
      <p>
        Columns with defaultFlex values of 3, 2, and 1.
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

bool
default: false

The columns can be locked to the start or to the end of the <ReactDataGrid />.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'name', header: 'Name - defaultLocked', defaultLocked: true, defaultWidth: 200},
  { name: 'email', header: 'Email', defaultWidth: 250 },
  { name: 'city', header: 'City', defaultWidth: 250  },
  { name: 'country', header: 'Country', defaultWidth: 250,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultWidth: 250 },
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Make sure the columns do not fit the window, to force the horizontal scroll
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Determines whether a column is initially visible or not. Set this to false if you want to hide a column. If not specified (so column.defaultVisible is undefined), the column will be visible.
This is an uncontrolled prop. For the controlled version, use visible.
If you use the controlled prop, make sure you update the column visible prop value when onColumnVisibleChange({ column, visible }) is triggered.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', type: 'number', defaultWidth: 80, defaultVisible: false },
  { name: 'firstName', header: 'Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', defaultVisible: false, minWidth: 150 },
  { name: 'country', header: 'Country', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Id column and email column is not visible by default. You can enable it from the header menu.
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

Configures the column size - uncontrolled.
This is an uncontrolled prop. For the controlled alternative, see column.width.
Minimum and maximum dimensions can be specified via column.minWidth and column.maxWidth.
This overrides columnDefaultWidth.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', heder: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', defaultWidth: 210, header: 'Name, defaultWidth=210' },
  { name: 'city', defaultFlex: 1, header: 'City', minWidth: 110 },
  { name: 'email', header: 'Email, defaultWidth=210', defaultWidth: 210 },
  { name: 'country', header: 'Country', defaultFlex: 1, minWidth: 100,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', minWidth: 70, defaultFlex: 1, type: 'number' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Specifies if a specific column can be draggable or not.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = (state) => {
  return [
    { name: 'id', type: 'number', defaultWidth: 80, header: 'Id', defaultVisible: false },
    { name: 'firstName', defaultFlex: 1, draggable: state.draggable, header: 'First Name' },
    { name: 'country', defaultFlex: 1, draggable: state.draggable, header: 'Country' },
    { name: 'age', defaultFlex: 1, type: 'number', header: 'Age', draggable: state.draggable, header: 'Age' }
  ]
}

const App = () => {
  const [draggable, setDraggable] = useState(true)
  const [columns, setColumns] = useState(getColumns({ draggable }))

  const onDraggableChange = useCallback((value) => {
    setDraggable(value)
    setColumns(getColumns({ draggable: value }))
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={draggable} onChange={onDraggableChange}>
          Draggable
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool|Function(editValue, cellProps)
default: undefined

Specifies whether a column (or cell, if editable is a function) should have inline edit enabled or not.
If the value is a function, it can either return a boolean value, or a Promise. In case a Promise is returned, if it is rejected or resolved with false, the cell is not editable. If the returned Promise is resolved with true, the cell is editable.
Overrides editable
.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = (state) => {
  return [
    { name: 'id', type: 'number', defaultWidth: 80, header: 'Id', defaultVisible: false },
    { name: 'name', defaultFlex: 1, editable: state.editable, header: 'Name' },
    { name: 'country', defaultFlex: 1, minWidth: 80, header: 'Country' },
    { name: 'city', defaultFlex: 1, editable: state.editable, header: 'City' },
    { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
  ]
}

const App = () => {
  const [editable, setEditable] = useState(true)
  const [dataSource, setDataSource] = useState(people)
  const [columns, setColumns] = useState(getColumns({ editable }))

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data)
  }, [dataSource])

  const onEditableChange = useCallback((editable) => {
    setEditable(editable)
    setColumns(getColumns({ editable }))
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={editable} onChange={onEditableChange}>
          Make Name and City columns editable
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

React.Node
default: undefined

Specifies a custom editor for each column. The <ReactDataGrid /> supports this feature, so you can specify your own column.editor, which should be a React Component.
If neither column.editor, nor column.renderEditor are specified, a default text editor is used for editing.
When writing a custom column editor, via column.editor or column.renderEditor(editorProps) it is important that you call editorProps.onChange and editorProps.onComplete accordingly, when the user changes the value in the editor and when it completes/cancels the edit. It's also important that you call editorProps.onTabNavigation(complete: bool, direction) so that the user can navigate from the editor to other editors in the row (either backwards or forwards - direction should be -1 for backwards and 1 for forwards).
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumericEditor from '@inovua/reactdatagrid-community/NumericEditor'
import BoolEditor from '@inovua/reactdatagrid-community/BoolEditor'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', type: 'number', defaultFlex: 1, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'age', defaultFlex: 1, editor: NumericEditor, header: 'Age' },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => value? 'Yes':'No',
    editor: BoolEditor,
    editorProps: {
      style: { background: '#444d65' }
    }
  },
  { name: 'country', defaultFlex: 1, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' }
]

const initialData = people.map(p=>Object.assign({}, p))

const App = () => {
  const [dataSource, setDataSource] = useState(initialData)

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data)
  }, [dataSource])

  return (
    <div style={{marginBottom: 20}}>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable={true}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Inline edit wouldn't be very useful unless you can specify custom editors for each column. The<ReactDataGrid /> supports this feature, so you can specify your own column.editor, which should be a React Component. If you simply want to override the props of the default column editor, you can use editorProps to do so.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumericEditor from '@inovua/reactdatagrid-community/NumericEditor'
import BoolEditor from '@inovua/reactdatagrid-community/BoolEditor'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', defaultFlex: 1, minWidth: 200, maxWidth: 300, header: 'Name' },
  { name: 'age', defaultFlex: 1, type: 'number', editor: NumericEditor, header: 'Age' },
  { name: 'student',
    header: 'Student',
    width: 100,
    editor: BoolEditor,
    render: ({ value }) => value? 'Yes':'No',
    editorProps: {
      style: { background: 'rgba(121, 134, 203, 0.25)' }
    }
  },
  { name: 'country', defaultFlex: 1, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' }
]

const App = () => {
  const [dataSource, setDataSource] = useState(people);

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data);
  }, [dataSource])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable={true}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool|Number
default: 250

If a numeric value is specified, it is used to delay (actually debounce) the filtering for the column, as the user is typing and changing the filter value.
When false or 0, no delay is used.
In most cases, using a filtering delay is highly recommended, both for the user experience & performance.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', defaultFlex: 1, filterDelay: 500, hedaer: 'Name' },
  { name: 'country', defaultFlex: 1,
    hedaer: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

React.Component
default: undefined

Specifies the editor that should be used for the filter.
The filter editors are not embeded in the <ReactDataGrid />, but have to be explicitly imported. Here is the list of available imports:
  • @inovua/reactdatagrid-enterprise/StringFilter
  • @inovua/reactdatagrid-community/NumberFilter
  • @inovua/reactdatagrid-community/BoolFilter
  • @inovua/reactdatagrid-community/SelectFilter
  • @inovua/reactdatagrid-community/DateFilter
The specified React.Component should have a setValue(value) public method to allow setting the filter value imperatively.
The filter editor receives a render prop (which is a function), that accepts any React.Node as a parameter. So the filter editor should return the result of the this.props.render(any jsx) call on its render method.
Below you can find the implementation of the StringFilter editor.
import React from 'react';

import debounce from 'lodash.debounce';

class StringFilter extends React.Component {
  constructor(props) {
    super(props);

    const { filterValue } = props;

    this.state = {
      value: filterValue ? filterValue.value : ''
    };
    this.onChange = this.onChange.bind(this);
    this.onValueChange = this.onValueChange.bind(this);

    if (props.filterDelay && props.filterDelay >= 1) {
      this.onValueChange = debounce(this.onValueChange, props.filterDelay, {
        leading: false,
        trailing: true
      });
    }
  }

  onChange(event) {
    const value = event.target.value;

    this.onValueChange(value);

    this.setValue(value);
  }

  setValue(value) {
    this.setState({
      value
    });
  }

  onValueChange(value) {
    this.props.onChange(Object.assign({}, this.props.filterValue, { value }));
  }

  render() {
    let { filterValue, readOnly, style } = this.props;

    const inputProps = {
      readOnly,
      style: Object.assign({}, { minWidth: 0 }, style)
    };

    if (filterValue) {
      inputProps.value = this.state.value;
    }

    return this.props.render(
      <input
        type="text"
        onChange={this.onChange}
        className="inovua-react-datagrid__column-header__filter inovua-react-datagrid__column-header__filter--string"
        {...inputProps}
      />
    );
  }
}
As seen in the code above, the filter editor should keep it's value in the state. It's also important for the filter to have a setValue method, to be called when people use the column header menu to clear the filter value, or when clearColumnFilter is called by the user.
Also note the return value from the render function:
render(){
  // ... other code here
  return this.props.render(
    <input
      type="text"
      onChange={this.onChange}
      className="..."
      {...inputProps}
    />
  );
}
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumberFilter from '@inovua/reactdatagrid-community/NumberFilter'
import BoolFilter from '@inovua/reactdatagrid-community/BoolFilter'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterTypes = Object.assign({}, ReactDataGrid.defaultProps.filterTypes, {
  country: {
    name: 'country',
    operators: [
      {
        name: 'europe',
        fn: ({ value, filterValue, data }) => {
          if (filterValue == null) {
            return true
          }
          const isInEurope = value != 'usa' && value != 'ca'

          return filterValue ?
            isInEurope :
            !isInEurope
        }
      }
    ]
  }
})

const filterValue = [
  { name: 'country', operator: 'europe', type: 'country', value: true },
  { name: 'age', operator: 'gte', type: 'number', minWidth: 200, value: 21 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, maxWidth: 100, type: 'number' },
  { name: 'name', defaultFlex: 1, maxWidth: 200, header: 'Name' },
  { name: 'country',
    header: 'Country - with Europe checkbox filter',
    defaultFlex: 1,
    filterEditor: BoolFilter,
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, minWidth: 200, header: 'City' },
  { name: 'age', minWidth: 150, type: 'number', filterEditor: NumberFilter, header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object|Function
default: undefined

Allows customization of the filter editor that is used for filtering for this column. The filter editor is used based on the value specified by filterEditor.
For more complex use-cases, you can specify a function, which should return a an object to be used as the props for the filter editor. This is especially useful when implementing dynamic functionality or configuring the props for inrange/notinrange editors.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumberFilter from '@inovua/reactdatagrid-community/NumberFilter'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, maxWidth: 100, type: 'number' },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 200, maxWidth: 300,

    filterEditorProps: { style: { background: 'rgba(121, 134, 203, 0.25)' } }
  },
  { name: 'age', defaultFlex: 1, type: 'number', filterEditor: NumberFilter, header: 'Age' },
  { name: 'country', defaultFlex: 1, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
      <p>Delete the filters if you want to show all data. You can click the configure icon and then "Clear All"</p>
    </div>
  );
}

export default () => <App />

String
default: undefined

Specifies the filter type. Is overridden by filterValue.type.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumberFilter from '@inovua/reactdatagrid-community/NumberFilter'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, maxWidth: 100, type: 'number' },
  { name: 'name', defaultFlex: 1, minWidth: 200, maxWidth: 300, filterType: 'string', header: 'Name' },
  { name: 'age', defaultFlex: 1, type: 'number', filterEditor: NumberFilter, header: 'Age' },
  { name: 'country', defaultFlex: 1, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
      <p>Delete the filters if you want to show all data. You can click the configure icon and then "Clear All"</p>
    </div>
  );
}

export default () => <App />

Number
default: undefined

Specifies the flex amount for the column.
This is a controlled property. For the uncontrolled alternative, seecolumn.defaultFlex.
It works similarly to browser flex-box: substracts the total fixed column widths from the total available space, then divides this by the sum of all flexes and multiplies that value with the flex value of each flexible column.
Additionally, column.minWidth and column.maxWidth can be configured for both fixed and flexible columns in order to ensure some minimum or maximum dimensions are always respected.
For the uncontrolled version, see related column.defaultFlex
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const defaultColumns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'First Name', flex: 3 },
  {
    name: 'country',
    header: 'Country',
    flex: 2,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', flex: 1 }
]

const App = () => {
  const [columns, setColumns] = useState(defaultColumns)

  const onBatchColumnResize = useCallback((batchColumnInfo) => {
    const colsMap = batchColumnInfo.reduce((acc, colInfo) => {
      const { column, flex} = colInfo
      acc[column.name] = { flex }
      return acc
    }, {})

    const cols = columns.map(c => {
      return Object.assign({}, c, colsMap[c.name])
    })

    setColumns(cols)
  }, [columns])

  return (
    <div>
      <p>
        Columns with flex values of 3, 2, and 1.
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        onBatchColumnResize={onBatchColumnResize}
      />
    </div>
  );
}

export default () => <App />

Function(editValue, cellProps)
default: undefined

When starting inline edit on a cell in the column, you can override the edit start value, using this function. It can either return immediately, or return a Promise. The resolve value of the returned Promise will be the actual value used when starting the edit.
The editValue passed to the function is the current value in the cell.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = (state) => {
  return [
    { name: 'id', type: 'number', defaultWidth: 80, editable: false, header: 'Id', defaultVisible: false },
    { name: 'name', header: 'Name', defaultFlex: 1, getEditStartValue: (value) => Promise.resolve(value + '!!!') },
    { name: 'country', defaultFlex: 1, minWidth: 80, header: 'Country' },
    { name: 'city', header: 'City', defaultFlex: 1, getEditStartValue: (value) => value + '!!!' },
    { name: 'age', header: 'Age', minWidth: 80, type: 'number', getEditStartValue: (value) => Promise.resolve(value + '!!!') }
  ]
}

const App = () => {
  const [editable, setEditable] = useState(true)
  const [dataSource, setDataSource] = useState(people)
  const [columns, setColumns] = useState(getColumns({ editable }))

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data)
  }, [dataSource])

  return (
    <div>
      <p>NAME, CITY and AGE columns start the edit by adding a "!!!" at the end of the actual value</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        editable
        onEditComplete={onEditComplete}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

To stack columns, you need to specify a column.group if you want a specific column to belong to a group.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, hedaer: 'Id', defaultVisible: false },
  { name: 'firstName', group: 'personalInfo', defaultFlex: 1, header: 'First Name' },
  { name: 'age', group: 'personalInfo', type: 'number', header: 'Age' },
  { name: 'email', group: 'contactInfo', defaultFlex: 1, header: 'Email' },
  { name: 'phone', group: 'contactInfo', header: 'Phone'  },
  { name: 'city', group: 'location', header: 'City' },
  { name: 'streetName', group: 'street', defaultFlex: 1, header: 'Street name' },
  { name: 'streetNo', group: 'street', type: 'number', header: 'Street no' }
]
const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', header: 'Personal info' },
  { name: 'contactInfo', header: 'Contact info' },
  { name: 'location', header: 'Location' }
]

const dataSource = [
  { id: 0, firstName: 'Bob', age: 25, email: 'bobby@whocares.com', phone: '+7403 456 768', city: 'Paris', streetName: 'Champs Elysee', streetNo: 34 },
  { id: 1, firstName: 'Lynda', age: 38, email: 'lynda@idont.com', phone: '+7103 66 98 768', city: 'London', streetName: 'St Mary', streetNo: 14 },
  { id: 2, firstName: 'Richard', age: 18, email: 'richy@rich.com', phone: '+173 668 08 83', city: 'Manchester', streetName: 'St Robert', streetNo: 53 },
  { id: 3, firstName: 'Michael', age: 45, email: 'mike@mikey.com', phone: '+075 0628 156 74', city: 'Los Angeles', streetName: 'Greenfield', streetNo: 24 },
  { id: 4, firstName: 'Martin', age: 12, email: 'martin@bobson.com', phone: '+173 5624 675 462', city: 'San Jose', streetName: 'Patrick Ball', streetNo: 67 }
]
const gridStyle = { minHeight: 500 }

export default () => <div>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>

Bool
default: undefined

If you don't want a certain column to be draggable in the grouping toolbar, specify column.groupBy=false.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, groupBy: false, type: 'number', defaultWidth: 50 },
  { name: 'firstName', header: 'First Name', defaultWidth: 150 },
  { name: 'lastName', header: 'Last Name', defaultWidth: 150 },
  { name: 'email', header: 'Email', groupBy: false, defaultWidth: 150 },
  {
    name: 'permissionToCall',
    header: 'Permission to call',
    defaultWidth: 200,
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
  }
];

const loadData = ({ skip, limit, sortInfo, groupBy }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '') + (groupBy && groupBy.length ? '&groupBy=' + groupBy : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [stickyGroupRows, setStickyGroupRows] = useState(false);
  const [groupBy, setGroupBy] = useState([]);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <p><Button onClick={() => setGroupBy(['permissionToCall', 'lastName'])}>Group by permissionToCall and lastName</Button></p>
      <p><Button onClick={() => setGroupBy([])}>Remove grouping</Button></p>
      <p>In this example, you cannot group by id or email.</p>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={stickyGroupRows}
          onChange={setStickyGroupRows}
        >
          Use sticky group rows
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        stickyGroupRows={stickyGroupRows}
        groupBy={groupBy}
        onGroupByChange={setGroupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

{ initialValue: any, reducer: (acc, current) => any, complete: (value, arr) => any}
default: undefined

Specifies how to compute a summary for the current column when there is grouping.
The groupSummaryReducer object has the following shape:
  • initialValue - the initial value to be used for the summary computation - generally a number/string/etc
  • reducer(accumulator, currentValue) - the reducer function - basically computes the summary from the accumulated value (at first call, this will equal the initialValue) and the current value for the item at which we are doing the computation
  • complete(accumulatedValue, array) - can be used for doing one last computation at the end of the iteration - for example useful for computing the average of a value. The first argument is the accumulated value, while the second is the array on which the summary was computed against
To use non-column specific grouping, see groupSummaryReducer.
In custom render functions defined for columns, when the group row is being rendered, you have access to the group summaries via the data.groupColumnSummary object, which has a key for each of the columns that define a column.groupSummaryReducer.
Also data.groupSummary is available in the render function in case you have definedgroupSummaryReducer at grid-level.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

const gridStyle = { minHeight: 600, marginTop: 10 }

let cities;

const sum = (a,b) => a + b;

const columns = [
  { name: 'name', defaultFlex: 1, header: 'City' },
  { name: 'country', defaultFlex: 1, header: 'Country' },
  {
    name: 'population',
    type: 'number',
    defaultFlex: 1,
    header: 'Population',

    render: ({ value, data, cellProps: {summaryProps} }) => {
      // if you want to custom-render the summary value for this column
      // you can do so

      return summaryProps ? (
        <React.Fragment>
          <b>Total: </b>
          {value}{' '}
        </React.Fragment>
      ) : (
        value
      );
    },

    groupSummaryReducer: {
      initialValue: 0,
      reducer: sum,
    },
  },
];

const App = () => {
  const [showGroupSummaryRow, setShowGroupSummaryRow] = useState(true);

  const renderGroupTitle = useCallback((value, { data }) => {
    let summary = null;

    if (data.groupColumnSummary) {
      summary = (
        <b> Total Population: {data.groupColumnSummary.population}</b>
      );
    }

    return (
      <div>
        {value}
        {summary}
      </div>
    );
  }, [])

  return (
    <div>
      <h3>Group summary row position demo</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showGroupSummaryRow}
          onChange={setShowGroupSummaryRow}
        >
          Show group summary row
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        showGroupSummaryRow={showGroupSummaryRow}
        columns={columns}
        dataSource={cities}
        defaultGroupBy={['country']}
        renderGroupTitle={renderGroupTitle}
      />
    </div>
  );
}

cities = [
  {
    id: 'ny',
    country: 'USA',
    name: 'New York City',
    population: 1000
  },
  {
    id: 'la',
    country: 'USA',
    name: 'Los Angeles',
    population: 150
  },
  {
    id: 'paris',
    country: 'France',
    name: 'Paris',
    population: 2000
  },
  {
    id: 'london',
    name: 'London',
    country: 'UK',
    population: 3000
  },
  {
    id: 'SF',
    name: 'San Francisco',
    country: 'USA',
    population: 3900
  },
  {
    id: 'ly',
    name: 'Lyon',
    country: 'France',
    population: 980
  },
  {
    id: 'ma',
    name: 'Manchester',
    country: 'UK',
    population: 2000
  }
]

export default () => <App />;

Fn(value)
default: undefined

Specifies a custom function to return the grouping value.
When no column.renderGroupTitle is specified, this function is used instead for rendering the group title.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

const europeCities = {
  Paris: true,
  London: true,
  Manchester: true
}

const cityToString = (city) => {
  if (!city) {
    return 'unknown'
  }

  if (city.name in europeCities) {
    return 'europe'
  }
  return 'us'
}

const dataSource = [
  { id: 0, firstName: 'Bob', age: 25, email: 'bobby@whocares.com', phone: '+7403 456 768', city: {name: 'Paris'}, streetName: 'Champs Elysee', streetNo: 34 },
  { id: 1, firstName: 'Lynda', age: 38, email: 'lynda@idont.com', phone: '+7103 66 98 768', city: {name: 'London'}, streetName: 'St Mary', streetNo: 14 },
  { id: 2, firstName: 'Richard', age: 18, email: 'richy@rich.com', phone: '+173 668 08 83', city: {name: 'Manchester'}, streetName: 'St Robert', streetNo: 53 },
  { id: 3, firstName: 'Michael', age: 45, email: 'mike@mikey.com', phone: '+075 0628 156 74', city: {name: 'Los Angeles'}, streetName: 'Greenfield', streetNo: 24 },
  { id: 4, firstName: 'Martin', age: 12, email: 'martin@bobson.com', phone: '+173 5624 675 462', city: {name: 'San Jose'}, streetName: 'Patrick Ball', streetNo: 67 }
]

const columns = [
  { name: 'id', type: 'number', minWidth: 50, header: 'Id', defaultVisible: false },
  { name: 'city',
    header: 'City',
    minWidth: 100,
    flex: 1,
    groupToString: cityToString,
    render: ({ value: city }) => city ? city.name : null,
    renderGroupTitle: (city) => {
      if (!city) {
        return 'unknown'
      }

      if (city.name in europeCities) {
        return 'Cities in Europe'
      }
      return 'Cities in US'
    }
  },
  { name: 'firstName', defaultFlex: 1, minWidth: 120, header: 'First Name' },
  { name: 'age', type: 'number', defaultFlex: 1, minWidth: 70, header: 'Age' },
  { name: 'email', defaultFlex: 1, header: 'Email', minWidth: 170 },
  { name: 'phone', defaultFlex: 1, header: 'Phone', minWidth: 150 },
  { name: 'streetName', defaultFlex: 1, header: 'Street name', minWidth: 120 },
  { name: 'streetNo', type: 'number', minWidth: 120, defaultFlex: 1, header: 'Street no' }
]

const App = () => {
  return (
    <div>
      <p>The "city" column has a custom grouping function.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={["city"]}
        hideGroupByColumns={false}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

React.Node|Fn(columnProps, info)
default: undefined

By adding a columns.header prop (any valid React.Node or even a function) you can have full control over what gets rendered as the column header - even for different states of the column (sorted, filtered, etc).
The second object passed to the column.header function provides additional info about the column header. For example, you can use info.contextMenu to know if the header function is currently called for rendering the column name/header in the <ReactDataGrid /> column context menu.
The same column.header function is called when rendering the column header in three different scenarios:
  • for the normal column header position - called like column.header(cellProps, { cellProps, column, headerProps })
    Note that cellProps is an object that contains all the column properties, but in addition also contains useful information about the header cell.
    When column.header is called for the normal column header, the headerProps property is present on the second parameter to the function call.
  • for the column context menu - when listing the current column in the show/hide columns menu - called like column.header(cellProps, { column, contextMenu }).
    When column.header is called for the show/hide columns menu, the contextMenu property is present on the second parameter to the function call.
  • for the grouping toolbar item - when the <ReactDataGrid /> is grouped by the current column - called like column.header(column, { column, group: true })
    When column.header is called for the grouping toolbar item when grouping by the current column, neither headerProps nor contextMenu properties are present on the second parameter to the function call. Instead, a boolean group prop is present.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: <h3 style={{margin: 0, color: 'tomato', fontWeight: 'bold'}}>First Name</h3> },
  { name: 'city', defaultFlex: 1,
    header: ({ sortInfo }, { contextMenu }) => {
      const sorted = sortInfo && sortInfo.name === 'city' ? ' sorted' : '';
      const sortOrder = sorted ? (sortInfo.dir === 1 ? ' ASC' : ' DESC') : ''

      return 'City'+sorted+sortOrder + (contextMenu ? ' (context menu)': '')
    }
  },
  { name: 'age', header: 'Current age', maxWidth: 400, defaultWidth: 150, type: 'number' }
]

export default () => <ReactDataGrid
  style={gridStyle}
  idProperty="uniqueId"
  columns={columns}
  dataSource={people}
/>

String
default: undefined

A value for horizontally aligning column header contents.
If column.headerAlign is not specified, column.textAlign will be used for aligning content in the column header.
Valid values are: "start", "center" and "end". By default, column header contents are naturally aligned by the browser, so they get "start"-aligned.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1, headerAlign: 'start' },
  { name: 'city', header: 'City', defaultFlex: 1, headerAlign: 'center' },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1, headerAlign: 'end' }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Columns with headerAlign none, start, center and end
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

An object with DOM props to be applied to the column header. It can contain any valid DOM properties, like className, style or onClick.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const countryStyle = {
  color: '#7986cb'
}
const redColor = {
  color: '#ef9a9a'
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', defaultFlex: 1, minWidth: 100, header: 'Name', headerDOMProps: { style : redColor } },
  { name: 'country', headerDOMProps: { style: countryStyle }, defaultFlex: 1, minWidth: 100, header: 'Country' },
  { name: 'city', defaultFlex: 1, minWidth: 100, header: 'City' },
  { name: 'age', minWidth: 150, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Whether the column header contents should show ellipsis when the header text is too long.
When using custom rendering (unless you render plain text via the configured column.header), ellipsis will no longer work since you are changing the nesting & layout of the column header. In this case, you have to take care of showing the text ellipsis yourself by adding the correct styles to the correct elements to make it work as desired.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = ({ textEllipsis }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
    { name: 'name', header: 'Name', defaultFlex: 1 },
    { name: 'city', header: 'City', defaultFlex: 1 },
    {
      id: 'description',
      defaultFlex: 1,
      maxWidth: 150,
      textEllipsis,
      headerEllipsis: textEllipsis,
      header: 'Description column to test ellipsis',
      render: ({ data }) => data.name + ', aged: ' + data.age + '. Lives in ' + data.country
    }
  ]
}

const App = () => {
  const [textEllipsis, setTextEllipsis] = useState(true)
  const [columns, setColumns] = useState(getColumns({ textEllipsis }))

  const onTextEllipsisChange = useCallback((textEllipsis) => {
    setTextEllipsis(textEllipsis)
    setColumns(getColumns({ textEllipsis }))
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={textEllipsis}
          onChange={onTextEllipsisChange}
        >
          Show text ellipsis on description header and column.
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Specifies whether the column header is text-selectable by the user.
For configuring text-selection in the column cells, use columns.userSelect.
import React, { useState, useCallback } from 'react'

import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = ({ headerUserSelect }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'name', header: 'Name - double-click to test selection', defaultFlex: 1, minWidth: 250, headerUserSelect },
    { name: 'age', minWidth: 250, defaultFlex: 1, header: 'Double-click to select', headerUserSelect: true }
  ]
}

const App = () => {
  const [headerUserSelect, setHeaderUserSelect] = useState(true);
  const [columns, setColumns] = useState(getColumns({ headerUserSelect }))

  const headerUserSelectHandle = useCallback((value) => {
    setHeaderUserSelect(value);
    setColumns(getColumns({ headerUserSelect: value }));
  }, [])

  return (
    <div>
      <div>
        <CheckBox checked={headerUserSelect} onChange={headerUserSelectHandle}>
          Enable browser text selection in headers
        </CheckBox>
      </div>
      <p>The last column header is always selectable, since it's configured with headerUserSelect: true</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        sortable={false}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

A value for vertically aligning column header contents.
If column.headerVerticalAlign is not specified, column.textVerticalAlign will be used for vertically aligning content in the column header.
Valid values are: "top", "center" (or "middle") and "bottom". By default, column header contents are vertically "middle"-aligned.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1, headerVerticalAlign: 'top' },
  { name: 'city', header: 'City', defaultFlex: 1, headerVerticalAlign: 'middle' },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number', headerVerticalAlign: 'bottom' }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Header columns with headerVerticalAlign none, top, middle and bottom
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowHeight={70}
        headerHeight={100}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

If you want to make the column not hideable via the column context menu, set this to false.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = ({ nameHideable }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'name', defaultFlex: 1, hideable: nameHideable, header: 'Name' },
    { name: 'country', defaultFlex: 1, minWidth: 80, header: 'Country' },
    { name: 'city', defaultFlex: 1, header: 'City' },
    { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
  ]
}

const App = () => {
  const [nameHideable, setNameHideable] = useState(false);
  const [columns, setColumns] = useState(getColumns({ nameHideable }))

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={nameHideable}
          onChange={(nameHideable) => {
            setNameHideable(nameHideable);
            setColumns(getColumns({ nameHideable }));
          }}
        >
          Can hide Name column
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

An identifier for the column. Each column needs either an id or a name, which should both be unique.
When a column.id is used, you need to use the column.render({data}) function in order to render content for the column cells.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultWidth: 100,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    defaultFlex: 2,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

If you want to make a column unlockable, set this to false. For the most part, this prop is an alias to columns.showColumnMenuLockOptions.
Overrides lockable

Bool
default: false

The columns can be locked to the start or to the end of the <ReactDataGrid />.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = (lockStart, lockEnd) => {
  const lockedStartProps = lockStart ? { locked: 'start' } : { locked: false };
  const lockedEndProps = lockEnd ? { locked: 'end' } : { locked: false };

  return [
    { name: 'Id', header: 'Id', defaultVisible: false },
    Object.assign({ name: 'name', header: 'Name', defaultWidth: 250 }, lockedStartProps),
    { name: 'email', header: 'Email', defaultWidth: 250 },
    Object.assign({ name: 'city', header: 'City', defaultWidth: 250}, lockedEndProps),
    { name: 'country', header: 'Country', defaultWidth: 250,
      render: ({ value }) => flags[value] ? flags[value] : value
    },
    { name: 'age', header: 'Age', defaultWidth: 250 }
  ]
}

const App = () => {
  const [lockStart, setLockStart] = useState(true)
  const [lockEnd, setLockEnd] = useState(false)
  const [columns, setColumns] = useState(getColumns('start'))

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        Make sure the columns do not fit the window, to force the horizontal scroll
      </div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={lockStart}
          onChange={value => {
            setLockStart(value)
            setColumns(getColumns(value, lockEnd))
          }}
        >
          Lock at start
        </CheckBox>
        <CheckBox
          style={{ marginLeft: 16 }}
          checked={lockEnd}
          onChange={value => {
            setLockEnd(value)
            setColumns(getColumns(lockStart, value))
          }}
        >
          Lock at end
        </CheckBox>
      </div>
      <ReactDataGrid
        key={'grid-' + lockStart + lockEnd}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

Specifies the maximum width a column can have.
resizable columns cannot be user-resized to have a bigger size, neither can flexible columns stretch more that the specified maximum width.
For minimum size restrictions, see column.minWidth.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 80 },
  { name: 'firstName', header: 'Name maxWidth 200', defaultFlex: 2 },
  {
    name: 'country',
    header: 'Country maxWidth 250',
    maxWidth: 250,
    defaultFlex: 3,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultFlex: 1 }
];

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnMaxWidth={200}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

Specifies the minimum width a column can have.
resizable columns cannot be user-resized to be smaller than the specified minimum size, neither can flexible columns shrink to be smaller than the specified min-width.
For maximum size restrictions, see column.maxWidth.
This overrides columnMinWidth (which defaults to 50).
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', minWidth: 40, maxWidth: 40 },
  { name: 'firstName', header: 'Name default minWidth', minWidth: 200, defaultFlex: 1 },
  {
    name: 'country',
    header: 'Country default minWidth',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', header: 'Age default minWidth' }
];

const App = () => {
  return (
    <div>
      <p>Default column minWidth=150</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        columnMinWidth={150}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

A name for the column. It will generally match a property from the items in the dataSource.
There should be only one column with a given name in the grid! If an id is not specified, the name will be used as an identifier. As a consequence, the column.name or column.id should be unique.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { id: 'uid', header: '#', render: ({data}) => data.id, defaultWidth: 80 },
  { name: 'firstName', header: 'Name', defaultFlex: 1 },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Each column must have a name or an id. First column has no name, but a required id and a custom render function.
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(cellProps)
default: undefined

Called just before the cell content is rendered in this column. This prop can be used to intercept the rendering and modify existing props (eg: className, style).
Also see column.cellDOMProps, which is the last render hook before the cell contents get into the DOM.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const onCountryRender = (cellProps) => {
  cellProps.style.color = '#7986cb'
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', defaultFlex: 1, minWidth: 100, header: 'Name' },
  { name: 'country', onRender: onCountryRender, defaultFlex: 1, minWidth: 100, header: 'Country' },
  { name: 'city', defaultFlex: 1, minWidth: 100, header: 'City' },
  { name: 'age', minWidth: 150, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

(fieldValue, { data: object, field: string }) => string
default: undefined

Determines how the pivot value is computed for the corresponding column.
By default, for grouping and pivoting, the grid turns all object property values into strings (if the type of a value is 'string' or 'number' or 'boolean', it simply stringifies them with toString, otherwise it will use JSON.stringify)
We call this operation bucketing because we decide in which bucket/group a data item in the grid dataSource should be put - this determines which items go into a certain pivot group.
.
See related pivot prop.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import sales from './sales';

const currency = (v) => {
  const str = ("" + v).split("").reverse().map((c,i) => {
    if (i && i%3 === 0) {
      return c + ","
    }
    return c
  }).reverse().join('')
  return "$ " + str + ".00"
}

const gridStyle = { minHeight: 500, marginTop: 10 }

const sumReducer = {
  initialValue: 0,
  reducer: (a: number, b: number) => a + b,
};

const groupSummaryReducer = {
  initialValue: {
    count: 0,
    grandTotal: 0,
  },
  reducer: (v: { count: number; grandTotal: number }, item) => {
    return {
      count: v.count + 1,
      grandTotal: v.grandTotal + item.amount,
    };
  },
};

const quarterSumReducer = (monthFn: (m: number) => boolean) => {
  return {
    initialValue: 0,
    reducer: (acc: number, value: number, item: any) => {
      const month = parseInt(item.date.split('-')[1], 10);

      if (monthFn(month)) {
        return acc + item.amount;
      }
      return acc;
    },
  };
};

const columns = [
  { name: 'region', header: 'Region' },
  { name: 'country', header: 'Country' },
  { name: 'city', header: 'City' },
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    type: 'number',
    maxWidth: 100,
  },
  {
    id: 'year',
    name: 'date',
    header: 'Year',
    pivotToString: (_, { data }) => {
      return data.date.split('-')[0];
    },
  },
  {
    id: 'q1',
    defaultWidth: 150,
    header: 'Q1',
    name: 'amount',
    pivotName: 'q1',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month <= 3),
    render: ({ value }) => currency(value),
    textAlign: 'end'
  },

  {
    id: 'q2',
    defaultWidth: 150,
    header: 'Q2',
    name: 'amount',
    pivotName: 'q2',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month > 3 && month <= 6),
    render: ({ value }) => currency(value),
    textAlign: 'end'
  },

  {
    id: 'q3',
    defaultWidth: 150,
    header: 'Q3',
    pivotName: 'q3',
    name: 'amount',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month > 6 && month <= 9),
    render: ({ value }) => currency(value),
    textAlign: 'end'
  },

  {
    id: 'q4',
    defaultWidth: 150,
    header: 'Q4',
    pivotName: 'q4',
    name: 'amount',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month > 9 && month <= 12),
    render: ({ value }) => currency(value),
    textAlign: 'end'
  },
];

const summaryReducer = {
  initialValue: {
    total: 0
  },
  reducer: (acc, item, computedProps) => {
    const dateSplit = item.date.split('-');
    const year = parseInt(dateSplit[0], 10);
    const month = parseInt(dateSplit[1], 10);
    const quarter =
      year +
      '-' +
      (month <= 3 ? 'q1' : month <= 6 ? 'q2' : month <= 9 ? 'q3' : 'q4');

    if (!acc[year]) {
      acc[year] = 0;
    }
    if (!acc[quarter]) {
      acc[quarter] = 0;
    }
    acc[year] += item.amount;
    acc[quarter] += item.amount;
    acc.total += item.amount;

    return acc;
  },
};

const footerCellStyle = {
  textOverflow: 'ellipsis',
  width: '100%',
  whiteSpace: 'nowrap',
  overflow: 'hidden',
};

const pivot = [
  {
    name: 'year',
    summaryReducer: {
      initialValue: 0,
      reducer: (acc, value, item) => {
        const year = item.date.split('-')[0];

        if (year == value) {
          return acc + item.amount;
        }

        return acc;
      },
      complete: (value) => <b>{currency(value)}</b>
    },
    summaryColumn: ({ pivotSummaryPath }) => {
      return {
        header: 'Summary ' + pivotSummaryPath[0].value,
        textAlign: 'end',
        style: {
          color: '#7986cb'
        }
      };
    },
    summaryGroup: {
      headerAlign: 'center'
    }
  }
]

const App = () => {
  const [enablePivot, setEnablePivot] = useState(true)
  const [groupBy, setGroupBy] = useState(['region', 'city'])
  const [showPivotSummaryColumns, setShowPivotSummaryColumns] = useState(true)

  const updateArray = useCallback((arr, fn, keys, sortOrder) => {
    let sortOrderIndexes = (sortOrder || []).reduce((acc, value, index) =>{
      acc[value] = index
      return acc
    }, {})

    Object.keys(keys).forEach(columnName => {
      const checked = keys[columnName]
      if (checked) {
        if (arr.indexOf(columnName) === -1) {
          arr = [...arr, columnName]
        }
      } else {
        if (arr.indexOf(columnName) !== -1) {
          arr = arr.filter(x=>x!=columnName)
        }
      }
    })

    if (sortOrder) {
      arr.sort((a,b) => sortOrderIndexes[a] - sortOrderIndexes[b])
    }

    fn(arr)
  }, [])

  const updateGroupBy = useCallback((keys) => {
    updateArray(groupBy, setGroupBy, keys,['region', 'country', 'city']);
  }, [groupBy])

  return (
    <div>
      <h3>Grid pivoted by year, with the column having pivotToString defined</h3>
      <div style={{ marginTop: 20}}>
        <CheckBox
          checked={showPivotSummaryColumns}
          onChange={setShowPivotSummaryColumns}
        >
          Show pivot summary columns
        </CheckBox>
      </div>
      <div style={{ marginTop: 20 }}>
        <CheckBox
          checked={groupBy.indexOf('region') !== -1}
          onChange={checked => updateGroupBy({ region: checked })}
        >
          Group by region
        </CheckBox>
      </div>
      <div style={{ marginTop: 20 }}>
        <CheckBox
          checked={groupBy.indexOf('country') !== -1}
          onChange={checked => updateGroupBy({ country: checked })}
        >
          Group by country
        </CheckBox>
      </div>

      <div style={{ marginTop: 20 }}>
        <CheckBox
          checked={groupBy.indexOf('city') !== -1}
          onChange={checked => updateGroupBy({ city: checked })}
        >
          Group by city
        </CheckBox>
      </div>

      <ReactDataGrid
        style={gridStyle}
        columns={columns}
        dataSource={sales}
        columnMinWidth={150}
        pivot={enablePivot ? pivot : null}
        groupBy={groupBy}
        showPivotSummaryColumns={showPivotSummaryColumns}
        pivotGrandSummaryColumn={{
          header: 'TOTAL',
          style: {
            color: '#ef9a9a',
            textAlign: 'right'
          },
          render: ({ data }) => <b>{currency(data.groupSummary.grandTotal)}</b>
        }}
        onGroupByChange={setGroupBy}
        groupSummaryReducer={groupSummaryReducer}
        groupColumn={{
          defaultFlex: 1,
          minWidth: 250,
          renderGroupValue: ({ value, groupSummary }) => (
            <React.Fragment>
              {value} ({groupSummary.count} records)
            </React.Fragment>
          ),
        }}
        summaryReducer={summaryReducer}
        footerRows={[
          {
            render: ({ column, summary }) => {
              const { pivotColumnPath, pivotSummaryPath, pivotGrandSummaryColumn, groupColumn } = column;

              let style = Object.assign({},footerCellStyle)

              if (groupColumn) {
                return <div style={style}>
                  <b>Total sales</b>
                </div>
              }

              style.textAlign = 'end'

              let result;

              if (pivotSummaryPath && pivotSummaryPath.length) {

                const pivotInfo = [...pivotSummaryPath].pop();
                const pivotValue = pivotInfo.value;

                result = summary[pivotValue];
                style.color = '#7986cb'

              } else  if (pivotColumnPath) {

                result = summary[(pivotColumnPath || []).join('-')] || 0;

              } else if (pivotGrandSummaryColumn) {

                result = summary.total;
                style.color = '#ef9a9a'

              }

              return (
                <div style={style}>
                  <b>{currency(result || 0)}</b>
                </div>
              );
            },
          },
        ]}
      />
    </div>
  );
}
export default () => <App />

Fn()
default: undefined

Columns configured with a name prop by default render the value in the corresponding property in the dataSource items.
Custom rendering (for all columns, either with a name or an id) is supported via the columns.render function prop. The columns.render is passed an object with the following properties:
  • value - if the column has a name, the value would be the value rendered if no columns.render property were configured.
  • data - the data object in the dataSource corresponding to the current row being rendered.
  • cellProps: Object - the props being passed to the cell corresponding to the current row and column.
    The cellProps: Object has a lot of properties you can use, here are some of them:
    • cellProps.data: Object - the data object backing the row
    • cellProps.value - the value to render for the cell
    • cellProps.rowIndex: Number
    • cellProps.columnIndex: Number
    • cellProps.inEdit: Bool - whether the cell is currently in edit mode
    • cellProps.editProps: Object - available when the cell is in edit mode
  • rowIndex: Number - the index of the current row being rendered.
  • rowSelected: Boolean - a boolean value indicating if the current row is selected or not.
  • rowActive: Boolean - a boolean value indicating if the current row is keyboard active or not.
  • cellSelected: Boolean - a boolean value indicating if the current cell is selected or not.
  • empty: Boolean - a boolean value indicating if the current row is an empty row or not.
  • totalDataCount: Number - the total count of rows that will be rendered.
  • rowExpanded: Boolean - a boolean value indicating if the current row is expanded or not.
  • toggleRowExpand: Function - if the <ReactDataGrid /> has row expand enabled - see expandedRows, this function will be present, and can be used to toggle the current row.
  • setRowExpanded: Function(Boolean) - if the <ReactDataGrid /> has row expand enabled - see expandedRows, this function will be present, and can be used to set the toggle state of the current row.
  • loadNodeAsync: Function() - calling it allows you to reload the current tree node (available when treeColumn is used) - loadNode or loadNodeOnce will be called for the current node.
  • toggleNodeExpand: Function() - calling it allows you to toggle the current tree node (available when treeColumn is used)
  • rendersInlineEditor - boolean flag indicating if the cell should have the inline editor rendered
The object passed to the columns.render function is reused - so you should not keep a reference to it. Instead, use ES6 destructuring to take the values you are interested in from this object.
The <ReactDataGrid /> column cells are optimized to only render when there is a change in the underlying dataSource, therefore, the column.render function should be pure. If not pure, and if the column.render uses variables defined outside of the function, make sure you specify columns.shouldComponentUpdate to return true.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import flags from './flags'

const gridStyle = { maxHeight: 207 }

const columns = [
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  {
    name: 'country',
    header: 'Country',
    defaultWidth: 100,
    textAlign: 'center',
    render: ({ value }) => flags[value] ? flags[value] : 'unknown'
  },
  { id: 'fullName', header: 'Full Name', minWidth: 100, defaultFlex: 1, render: ({ data }) => data.firstName + ' ' + data.lastName },
  {
    name: 'age',
    header: 'Age',
    defaultWidth: 80,
    render: ({ value }) => <span style={{ color: value < 30 ? '#7986cb' : 'inherit'}}>{value}</span>
  }
]

const dataSource = [
  { firstName: 'John', lastName: 'Grayner', country: 'usa', age: 35, id: 0 },
  { firstName: 'Mary', lastName: 'Stones', country: 'ca', age: 25, id: 1 },
  { firstName: 'Robert', lastName: 'Fil', country: 'uk', age: 27, id: 2 },
  { firstName: 'Mark', lastName: 'Twain', country: 'usa', age: 74, id: 3 }
]

export default () => <ReactDataGrid
  idProperty="id"
  columns={columns}
  dataSource={dataSource}
  style={gridStyle}
/>
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import TextInput from '../components/TextInput'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 400 }

const App = () => {
  const [gridRef, setGridRef] = useState(null);
  const [dataSource, setDataSource] = useState(people);
  const [searchText, setSearchText] = useState('');

  const render = useCallback(({ value }) => {
    const lowerSearchText = searchText && searchText.toLowerCase();
      if (!lowerSearchText) {
        return value
      }

    const str = value + '' // get string value
    const v = str.toLowerCase() // our search is case insensitive
    const index = v.indexOf(lowerSearchText)

    if (index === -1) {
      return value
    }

    return [
      <span key="before">{str.slice(0, index)}</span>,
      <span key="match" style={{ background: 'yellow', fontWeight: 'bold'}}>{str.slice(index, index + lowerSearchText.length)}</span>,
      <span key="after">{str.slice(index + lowerSearchText.length)}</span>
    ]
  }, [searchText])

  const shouldComponentUpdate = () => true

  const columns = [
    { name: 'id', header: 'Id', defaultVisible: false, minWidth: 50, type: 'number', render, shouldComponentUpdate },
    { name: 'name', defaultFlex: 1, render, shouldComponentUpdate, header: 'Name' },
    { name: 'country', defaultFlex: 1, minWidth: 100, render: ({ value })=> flags[value] ? flags[value] : value, shouldComponentUpdate, header: 'Country' },
    { name: 'city', defaultFlex: 1, minWidth: 100, render, shouldComponentUpdate, header: 'City' },
    { name: 'age', minWidth: 80, type: 'number',render, shouldComponentUpdate, header: 'Age' }
  ]

  const onSearchChange = useCallback(({ target: { value }}) => {
    const visibleColumns = gridRef.current.visibleColumns

    const lowerSearchText = value.toLowerCase();
    const newData = people.filter(p => {
      return visibleColumns.reduce((acc, col) => {
        const v = (p[col.id] + '').toLowerCase() // get string value
        return acc || v.indexOf(lowerSearchText) != -1 // make the search case insensitive
      }, false)
    })

    setSearchText(value);
    setDataSource(newData);
  }, [gridRef])

  return (
    <div>
      <p>
        We have to use <code>shouldComponentUpdate: () => true</code> for the columns rendering the search highlight, because they rely on external data (the render function is not pure), and yet we want them to be updated when the search text is updated.
      </p>
      <p>
        If not specifying the <code>shouldComponentUpdate: () => true</code>, the grid will not update the highlight when there is no change in the filtered rows, but yet the searchText changes  - eg: going from "Manche" to "Manchester")
      </p>
      <div style={{  marginBottom: 20 }}>
        <label>Search text: <TextInput style={{ padding: 5 }} value={searchText} onChange={onSearchChange}/> </label>
      </div>
      <p>
        We demo a search-box outside the grid. Use the search-box to filter out rows that do not contain the specified text.
      </p>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(editorProps)
default: undefined

Inline edit wouldn't be very useful unless you can specify custom editors for each column. The <ReactDataGrid /> supports this feature, so you can specify your own column.editor, which should be a React Component.
Or you can use column.renderEditor(editorProps) function and return a React.Node that describes your editor.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumericEditor from '@inovua/reactdatagrid-community/NumericEditor'
import BoolEditor from '@inovua/reactdatagrid-community/BoolEditor'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, minWidth: 200, maxWidth: 300, header: 'Name' },
  { name: 'age', defaultFlex: 1, type: 'number', editor: NumericEditor, header: 'Age' },
  { name: 'student',
    header: 'Student',
    width: 100,
    render: ({ value }) => value? 'Yes':'No',
    renderEditor: (editorProps) => {
      return <div
          tabIndex={0}
          autoFocus
          onClick={() => {
            editorProps.onChange(!editorProps.value)
          }}
          onBlur={editorProps.onComplete}
          onKeyDown={e => {
            if (e.key == 'Tab') {
              editorProps.onTabNavigation(
                true /*complete navigation?*/,
                e.shiftKey ? -1 : 1 /*backwards of forwards*/
              );
            }
          }}
          style={{
            cursor: 'pointer',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            position: 'absolute',
            width: '100%',
            height: '100%',
            background: '#434d64',
            color: '#9ba7b4',
            left: 0,
            top: 0
          }}
        >
          {editorProps.value ? 'X' : 'O'}
      </div>
    }
  },
  { name: 'country', defaultFlex: 1, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' }
]

const App = () => {
  const [dataSource, setDataSource] = useState(people);

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data);
  }, [dataSource])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable={true}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn({ value, name, fieldPath, ... }, rowProps)
default: undefined

This function prop can be used to customize how the group title is rendered for this column, in grids configured with groupBy.
Also available at grid-level, see renderGroupTitle
For custom grouping logic, see column.groupToString.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', groupBy: false, type: 'number', defaultWidth: 70, header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultWidth: 200, header: 'First Name' },
  { name: 'lastName', defaultWidth: 200, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultWidth: 200, header: 'Email' },
  {
    name: 'permissionToCall', defaultWidth: 200,
    header: 'Permission to call',
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
  }
]

const loadData = ({ skip, limit, sortInfo, groupBy }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '') + (groupBy && groupBy.length ? '&groupBy=' + groupBy : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [groupBy, setGroupBy] = useState([]);

  const dataSource = usecallback(loadData, [])

  return (
    <div>
      <p><Button onClick={() => setGroupBy(['permissionToCall', 'lastName'])}>Group by permissionToCall and lastName</Button></p>
      <p><Button onClick={() => setGroupBy([])}>Remove grouping</Button></p>
      <p>In this example, you cannot group by id or email.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        groupBy={groupBy}
        onGroupByChange={setGroupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(cellProps)
default: undefined

Specifies a custom render function for the header of a specific column. For example, it can be used to change the order of the column header text and the sort tool, as shown in the example below.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import arrowDown from './arrow-down.png'
import activeArrowDown from './active-arrow-down.png'
import flags from './flags'

const arrowStyle = {
  display: 'block',
  marginBottom: 2
};

const defaultStyle = {
  display: 'inline-block',
  marginRight: 5,
  width: 8,
  verticalAlign: 'middle'
};

const SortIndicator = ({ direction }) => {
  return <div style={defaultStyle}>
    <img
      src={direction === -1 ? activeArrowDown : arrowDown}
      style={Object.assign({ transform: 'rotate(180deg)' }, arrowStyle)}
    />
    <img
      src={direction === 1 ? activeArrowDown : arrowDown}
      style={arrowStyle}
    />
  </div>
};

const renderHeader = ({children}) => {
  return children.reverse() // reverse the order
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 120 },
  { name: 'firstName', header: 'Fist Name, unsortable', sortable: false, minWidth: 200, defaultFlex: 1, renderHeader },
  { name: 'lastName', header: 'Last Name', defaultFlex: 1, renderHeader },
  {
    name: 'country',
    header: 'Country',
    defaultWidth: 100,
    renderHeader,
    render: ({ value }) => flags[value] ? flags[value] : 'unknown'
  },
  { id: 'fullName', header: 'Full Name', renderHeader, minWidth: 50, defaultFlex: 1, render: ({ data }) => data.firstName + ' ' + data.lastName },
  {
    name: 'age',
    header: 'Age',
    type: 'number',
    renderHeader,
    defaultWidth: 80,
    render: ({ value }) => <span style={{ color: value < 30 ? 'green' : 'inherit'}}>{value}</span>
  }
]

const renderSortTool = (direction) => {
  return <SortIndicator direction={direction} />
}

const dataSource = [
  { firstName: 'John', lastName: 'Grayner', country: 'usa', age: 35, id: 0 },
  { firstName: 'Mary', lastName: 'Stones', country: 'ca', age: 25, id: 1 },
  { firstName: 'Robert', lastName: 'Fil', country: 'uk', age: 27, id: 2 },
  { firstName: 'Bob', lastName: 'Fisher', country: 'usa', age: 72, id: 3 },
  { firstName: 'Michael', lastName: 'Rogers', country: 'usa', age: 45, id: 4 },
  { firstName: 'Hilly', lastName: 'Bobson', country: 'uk', age: 5, id: 5 },
  { firstName: 'Mike', lastName: 'Brind', country: 'ca', age: 15, id: 6 },
  { firstName: 'Carl', lastName: 'Phancer', country: 'ca', age: 56, id: 7 },
  { firstName: 'Victory', lastName: 'Hope', country: 'uk', age: 52, id: 8 }
]

const gridStyle = { minHeight: 550 }
const defaultSortInfo = { name: 'age', dir: 1 }

export default () => <ReactDataGrid
  idProperty="id"
  columns={columns}
  style={gridStyle}
  defaultSortInfo={defaultSortInfo}
  renderSortTool={renderSortTool}
  dataSource={dataSource}
/>

bool|Fn(props)
default: undefined

When an editable column specifies rendersInlineEditor=true, it should use its render function to render an editor - which, when focused, starts the edit (so it saves the user a double click on the cell in order to start editing). The editor also participates in the edit keyboard navigation flow.
When a function is speficied, it's called with the same props object as the column.render function.
When rendersInlineEditor is a function, the result of the function will be available in the column.render function, as a property to the first argument.
import React, { useState, useEffect, useRef, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'
import TextInput from '../components/TextInput'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const Input = (props) => {
  const inputRef = useRef(null)

  useEffect(() => {
    if (inputRef && inputRef.current) {
      if (props.autoFocus) {
        inputRef.current.focus()
      }
    }
  }, [])

  return (
    <TextInput {...props} inputRef={inputRef} />
  );
}

const nameColumn = {
  name: 'name',
  header: 'Name',
  defaultFlex: 1, minWidth: 200,
  rendersInlineEditor: true,
  render: ({ value }, { cellProps }) => {
    let v = cellProps.editProps.inEdit
      ? cellProps.editProps.value
      : value;
    return (
      <Input
        type="text"
        autoFocus={cellProps.inEdit}
        value={v}
        onBlur={e => {
          cellProps.editProps.onComplete();
        }}
        onChange={cellProps.editProps.onChange}
        onFocus={() => cellProps.editProps.startEdit()}
        onKeyDown={e => {
          if (e.key === 'Escape') {
            cellProps.editProps.onCancel(e);
          }
          if (e.key === 'Enter') {
            cellProps.editProps.onComplete(e);
          }
          if (e.key == 'Tab') {
            e.preventDefault();
            cellProps.editProps.onTabNavigation(
              true,
              e.shiftKey ? -1 : 1
            );
          }
        }}
      />
    );
  }
}

const initialData = people.map(p=> Object.assign({}, p))

const columns = [
  { name: 'id', minWidth: 70, type: 'number', header: 'Id', defaultVisible: false },
  nameColumn,
  { name: 'country', defaultFlex: 1, minWidth: 100, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, minWidth: 200, header: 'City' },
  { name: 'age', minWidth: 150, type: 'number', header: 'Age' }
]

const App = () => {
  const [dataSource, setDataSource] = useState(initialData)

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex] = Object.assign({}, data[rowIndex], {[columnId]: value});

    setDataSource(data)
  }, [dataSource])

  return (
    <div>
      <h3>NAME column already renders an editor</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable={true}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(direction, extraProps)
default: undefined

Specifies a custom render function for the sort tool/icon for sortable columns. Overrides renderSortTool.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import arrowDown from './arrow-down.png'
import activeArrowDown from './active-arrow-down.png'
import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const arrowStyle = {
  display: 'block',
  marginBottom: 2
};

const defaultStyle = {
  display: 'inline-block',
  marginLeft: 5,
  width: 8,
  verticalAlign: 'middle'
};

const SortIndicator = ({ direction }) => {
  return <div style={defaultStyle}>
    <img
      src={direction === -1 ? activeArrowDown : arrowDown}
      style={Object.assign({ transform: 'rotate(180deg)' }, arrowStyle)}
    />
    <img
      src={direction === 1 ? activeArrowDown : arrowDown}
      style={arrowStyle}
    />
  </div>
};

const renderSortTool = (direction, extraProps) => {
  return <SortIndicator direction={direction} />
}

const defaultSortInfo = { name: 'age', dir: 1 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80, renderSortTool },
  { name: 'firstName', header: 'First Name', defaultFlex: 1, renderSortTool },
  { name: 'country', header: 'Country', defaultFlex: 1, renderSortTool,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1, renderSortTool }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        defaultSortInfo={defaultSortInfo}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Specifies whether the column is user-resizable or not.
When resized, columns respect their minimum and/or maximum sizes, if they are configured. When reaching the min/max limits, the resize proxy turns a different color to indicate the constrain has been hit.
For flexible columns, there's no need to update the width as a result of the resize.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ resizable }) => {
  return [
    { name: 'firstName', defaultFlex: 1, resizable, header: 'First Name' },
    { name: 'country', defaultFlex: 1, resizable, header: 'Country',
      render: ({ value }) => flags[value] ? flags[value] : value
    },
    {
      id: 'desc',
      header: 'Description',
      defaultFlex: 2,
      render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
    }
  ]
}

const App = () => {
  const [resizable, setResizable] = useState(true)
  const [columns, setColumns] = useState(getColumns({ resizable }))

  const onResizableChange = useCallback((resizable) => {
    setResizable(resizable)
    setColumns(getColumns({ resizable }))
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={resizable}
          onChange={onResizableChange}
        >
          Toggle resizable for the first two columns.
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, value, rowIndex, column, dataSourceArray })
default: undefined

Configures the rowspan for cells in the current column.
Please keep in mind that the grid has sorting/filtering/etc, so the same cells are not always siblings, as they can be sorted or filtered out or columns can be hidden or reordered.
Because of this, in the column.rowspanand column.colspan functions you have access to the data you need to make those truly dynamic.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    defaultWidth: 50,
    type: 'number'
  },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    rowspan: ({ value, dataSourceArray, rowIndex, column }) => {
      let rowspan = 1;

      const prevData = dataSourceArray[rowIndex - 1];
      if (prevData && prevData[column.name] === value) {
        return rowspan;
      }
      let currentRowIndex = rowIndex + 1;
      while (
        dataSourceArray[currentRowIndex] &&
        dataSourceArray[currentRowIndex][column.name] === value
      ) {
        rowspan++;
        currentRowIndex++;
        if (rowspan > 9) {
          break;
        }
      }
      return rowspan;
    }
  },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <h3>Rowspan example</h3>
      <p>
        Try and sort the <b>COUNTRY</b> column to see the cells with same country
        spanning together.
      </p>
      <ReactDataGrid
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn()
default: undefined

Needs to be used when you have a custom column.render function which is not pure, but uses variables from the outer context. Otherwise, if not using shouldComponentUpdate: () => true in these cases, you end up with the cells not being updated/re-rendered properly.
The <ReactDataGrid /> column cells are optimized to only render when there is a change in the underlying dataSource, therefore, the column.render function should be pure. If not pure, and if the column.render uses variables defined outside of the function, make sure you specify columns.shouldComponentUpdate to return true.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import TextInput from '../components/TextInput'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 400 }

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [dataSource, setDataSource] = useState(people);
  const [searchText, setSearchText] = useState('');

  const render = useCallback(({ value }) => {
    const lowerSearchText = searchText && searchText.toLowerCase();
      if (!lowerSearchText) {
        return value
      }

    const str = value + '' // get string value
    const v = str.toLowerCase() // our search is case insensitive
    const index = v.indexOf(lowerSearchText)

    if (index === -1) {
      return value
    }

    return [
      <span key="before">{str.slice(0, index)}</span>,
      <span key="match" style={{ background: 'yellow', fontWeight: 'bold'}}>{str.slice(index, index + lowerSearchText.length)}</span>,
      <span key="after">{str.slice(index + lowerSearchText.length)}</span>
    ]
  }, [searchText])

  const shouldComponentUpdate = () => true

  const columns = [
    { name: 'id', header: 'Id', defaultVisible: false, minWidth: 50, type: 'number', render, shouldComponentUpdate },
    { name: 'name', defaultFlex: 1, render, shouldComponentUpdate, header: 'Name' },
    { name: 'country', defaultFlex: 1, minWidth: 100, render: ({ value })=> flags[value] ? flags[value] : value, shouldComponentUpdate, header: 'Country' },
    { name: 'city', defaultFlex: 1, minWidth: 100, render, shouldComponentUpdate, header: 'City' },
    { name: 'age', minWidth: 80, type: 'number',render, shouldComponentUpdate, header: 'Age' }
  ]

  const onSearchChange = useCallback(({ target: { value }}) => {
    const visibleColumns = gridRef.current.visibleColumns

    const lowerSearchText = value.toLowerCase();
    const newData = people.filter(p => {
      return visibleColumns.reduce((acc, col) => {
        const v = (p[col.id] + '').toLowerCase() // get string value
        return acc || v.indexOf(lowerSearchText) != -1 // make the search case insensitive
      }, false)
    })

    setSearchText(value);
    setDataSource(newData);
  }, [gridRef])

  return (
    <div>
      <p>
        We have to use <code>shouldComponentUpdate: () => true</code> for the columns rendering the search highlight, because they rely on external data (the render function is not pure), and yet we want them to be updated when the search text is updated.
      </p>
      <p>
        If not specifying the <code>shouldComponentUpdate: () => true</code>, the grid will not update the highlight when there is no change in the filtered rows, but yet the searchText changes  - eg: going from "Manche" to "Manchester")
      </p>
      <div style={{  marginBottom: 20 }}>
        <label>Search text: <TextInput style={{ padding: 5 }} value={searchText} onChange={onSearchChange}/> </label>
      </div>
      <p>
        We demo a search-box outside the grid. Use the search-box to filter out rows that do not contain the specified text.
      </p>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Controls whether the menu of the current column displays the show/hide filtering row menu items.
This overrides showColumnMenuFilterOptions, at column-level.
If you want further customization for the column context menu, you can always use renderColumnContextMenu in order to have full control over what gets rendered in the menu.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
];

const getColumns = ({ showColumnMenuFilterOptions }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'name', defaultFlex: 1, showColumnMenuFilterOptions, header: 'Name' },
    { name: 'country', defaultFlex: 1,
      header: 'Country',
      render: ({ value })=> flags[value] ? flags[value] : value
    },
    { name: 'city', defaultFlex: 1, hedaer: 'City' },
    { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
  ]
}

const App = () => {
  const [showColumnMenuFilterOptions, setShowColumnMenuFilterOptions] = useState(true);
  const [columns, setColumns] = useState(getColumns({ showColumnMenuFilterOptions }));

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showColumnMenuFilterOptions}
          onChange={(showColumnMenuFilterOptions) => {
            setShowColumnMenuFilterOptions(showColumnMenuFilterOptions);
            setColumns(getColumns({ showColumnMenuFilterOptions }))
          }}
        >
          Display show/hide filtering row option for NAME column in column menu
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Controls whether the menu of the current column displays the group/ungroup menu items.
This overrides showColumnMenuGroupOptions, at column-level.
If you want further customization for the column context menu, you can always use renderColumnContextMenu in order to have full control over what gets rendered in the menu.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ showColumnMenuGroupOptions }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'name', defaultFlex: 1, showColumnMenuGroupOptions, header: 'Name' },
    { name: 'country', defaultFlex: 1,
      header: 'Country',
      render: ({ value })=> flags[value] ? flags[value] : value
    },
    { name: 'city', defaultFlex: 1, header: 'City' },
    { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
  ]
}

const App = () => {
  const [showColumnMenuGroupOptions, setShowColumnMenuGroupOptions] = useState(true);
  const [columns, setColumns] = useState(getColumns({ showColumnMenuGroupOptions }));

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showColumnMenuGroupOptions}
          onChange={(showColumnMenuGroupOptions) => {
            setShowColumnMenuGroupOptions(showColumnMenuGroupOptions);
            setColumns(getColumns({ showColumnMenuGroupOptions }));
          }}
        >
          Show group/ungroup loption for NAME column in column menu
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Controls whether the menu of the current column displays the lock/unlock menu items.
This overrides showColumnMenuLockOptions, at column-level.
If you want further customization for the column context menu, you can always use renderColumnContextMenu in order to have full control over what gets rendered in the menu.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ showColumnMenuLockOptions }) => [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, showColumnMenuLockOptions, header: 'Name' },
  { name: 'country', defaultFlex: 1,
    header: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  const [showColumnMenuLockOptions, setShowColumnMenuLockOptions] = useState(true);
  const [columns, setColumns] = useState(getColumns({ showColumnMenuLockOptions }));

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showColumnMenuLockOptions}
          onChange={(showColumnMenuLockOptions) => {
            setShowColumnMenuLockOptions(showColumnMenuLockOptions);
            setColumns(getColumns({ showColumnMenuLockOptions }))
          }}
        >
          Show lock/unlock option for NAME column in column menu
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Controls whether the menu of the current column displays the sort asc/desc/unsort menu items.
This overrides showColumnMenuSortOptions, at column-level.
If you want further customization for the column context menu, you can always use renderColumnContextMenu in order to have full control over what gets rendered in the menu.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ showColumnMenuSortOptions }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'name', defaultFlex: 1, showColumnMenuSortOptions, header: 'Name' },
    { name: 'country', defaultFlex: 1,
      header: 'Country',
      render: ({ value })=> flags[value] ? flags[value] : value
    },
    { name: 'city', defaultFlex: 1, header: 'City' },
    { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
  ];
}

const App = () => {
  const [showColumnMenuSortOptions, setShowColumnMenuSortOptions] = useState(true);
  const [columns, setColumns] = useState(getColumns({ showColumnMenuSortOptions }));

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showColumnMenuSortOptions}
          onChange={(showColumnMenuSortOptions) => {
            setShowColumnMenuSortOptions(showColumnMenuSortOptions);
            setColumns(getColumns({ showColumnMenuSortOptions }))
          }}
        >
          Show sort/unsort loption for NAME column in column menu
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Controls whether the current column header has menu integration enabled or not.
This overrides showColumnMenuTool, at column-level.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ showColumnMenuTool }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'name', defaultFlex: 1, showColumnMenuTool, header: 'Name' },
    { name: 'country', defaultFlex: 1,
      header: 'Country',
      render: ({ value })=> flags[value] ? flags[value] : value
    },
    { name: 'city', defaultFlex: 1, header: 'City' },
    { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
  ]
}

const  App = () => {
  const [showColumnMenuTool, setShowColumnMenuTool] = useState(true);
  const [columns, setColumns] = useState(getColumns({ showColumnMenuTool }));

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
      <CheckBox
        checked={showColumnMenuTool}
        onChange={(showColumnMenuTool) => {
          setShowColumnMenuTool(showColumnMenuTool);
          setColumns(getColumns({ showColumnMenuTool }))
        }}
        >
          Show NAME column header tool
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Controls whether the column headers menu displayed via showColumnMenuTool is displayed on mouse over, or all the time. Defaults to true if not a mobile device, and false if the component is rendered on a mobile device, where we want the menu tool to always be rendered.
This overrides showColumnMenuToolOnHover, at column-level.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ showColumnMenuToolOnHover }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'name', defaultFlex: 1, showColumnMenuToolOnHover, header: 'Name' },
    { name: 'country', defaultFlex: 1,
      header: 'Country',
      render: ({ value })=> flags[value] ? flags[value] : value
    },
    { name: 'city', defaultFlex: 1, header: 'City' },
    { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
  ];
}

const App = () => {
  const [showColumnMenuToolOnHover, setShowColumnMenuToolOnHover] = useState(true);
  const [columns, setColumns] = useState(getColumns({ showColumnMenuToolOnHover }));

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
      <CheckBox
        checked={showColumnMenuToolOnHover}
        onChange={(showColumnMenuToolOnHover) => {
          setShowColumnMenuToolOnHover(showColumnMenuToolOnHover);
          setColumns(getColumns({ showColumnMenuToolOnHover }))
        }}
        >
          Show NAME column header tool on hover
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(one, two, column)
default: undefined

Configures a custom sort function for the column. The provided function should always sort in ascending order.
When using a custom columns.sort function, make sure it always sorts in ascending order! For sorting in descending order, the <ReactDataGrid /> will take care to inverse the result of this function so as to obtain the correct sort order.
Make sure this columns.sort function respects the contract specified by Array.prototype.sort - so you need to make sure it can be passed to [].sort.
The columns.sort function will be called with the first two arguments being the corresponding values for the column from the dataSource (eg: for the age column, it would be called with two numbers, the age values from the currently compared records). The third argument is a reference to the column config, since you may need it sometimes (eg: when having a date column, specify a column.dateFormat which you can access in the sort function).
If the column specifying a columns.sort function does not have a columns.name property, columns.sort will be called with two arguments which are two items from the dataSource (as opposed to being called with the corresponding properties for the column extracted from those dataSource items).
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const dataSource = [
  { person: { name: 'Amanda Soaresz', age: 35 }, id: 0 },
  { person: { name: 'Mary Adamson', age: 25 }, id: 1 },
  { person: { name: 'Robert Fil', age: 27 }, id: 2 },
  { person: { name: 'Roger Bob', age: 81 }, id: 3 },
  { person: { name: 'Billary Konwik', age: 18 }, id: 4 },
  { person: { name: 'Bob Marc', age: 18 }, id: 5 },
  { person: { name: 'Matthew Richardson', age: 54 }, id: 6 },
  { person: { name: 'Richy Peterson', age: 54 }, id: 7 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  {
    name: 'person',
    header: 'Person',
    defaultFlex: 1,
    sortable: true,
    sort: (p1, p2) => p1.name.split(' ')[1].localeCompare(p2.name.split(' ')[1]),
    render: ({ data }) => { return <span>{data.person.name}</span> }
  },
  {
    name: 'age',
    header: 'Age',
    maxWidth: 400,
    defaultWidth: 200,
    type: 'number',
    render: ({ data }) => <span>{data.person.age}</span>
  }
]

const App = () => {
  return (
    <div>
      <p>
        In this example, you can sort the person column by the last name.
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        dataSource={dataSource}
        columns={columns}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Specifies whether the column should be sortable or not.
This overrides the grid-level sortable prop. See sortable for details on using sorting.
For rendering a custom sort tool/icon, see columns.renderSortTool.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ sortable }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
    { name: 'firstName', header: 'Name', defaultFlex: 1, sortable },
    { name: 'country', header: 'Country', defaultWidth: 100, sortable,
      render: ({ value }) => flags[value] ? flags[value] : value
    },
    { name: 'Age', header: 'Age - unsortable', defaultFlex: 1, sortable: false }
  ]
}

const App = () => {
  const [sortable, setSortable] = useState(true)
  const [columns, setColumns] = useState(getColumns({ sortable }))

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={sortable} onChange={value => {
          setSortable(value)
          setColumns(getColumns({ sortable: value }))
        }}>
          Sortable columns
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

A value for aligning text on the horizontal axis inside grid cells.
If column.headerAlign is not specified, column.textAlign will also be used for aligning content in the column header.
Valid values are: "start", "center" and "end". By default, cell contents are naturally aligned by the browser, so they get "start"-aligned.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultFlex: 1  },
  { name: 'name', header: 'Name', defaultFlex: 1, textAlign: 'start' },
  { name: 'city', header: 'City', defaultFlex: 1, textAlign: 'center' },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number', textAlign: 'end' }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Columns with textAlign none, start, center and end
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Whether the column cell contents should show ellipsis when the text is too long.
When using custom rendering (unless you are returning plain text from column.render), ellipsis will no longer work since you are changing the nesting & layout of the <ReactDataGrid /> cell. In this case, you have to take care of showing the text ellipsis yourself by adding the correct styles to the correct elements to make it work as desired.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = ({ textEllipsis }) => {
  return [
    { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
    { name: 'name', header: 'Name', defaultFlex: 1 },
    { name: 'city', header: 'City', defaultFlex: 1 },
    {
      id: 'description',
      defaultFlex: 1,
      maxWidth: 150,
      textEllipsis,
      header: 'Description',
      render: ({ data }) => data.name + ', aged: ' + data.age + '. Lives in ' + data.country
    }
  ]
}

const App = () => {
  const [textEllipsis, setTextEllipsis] = useState(true)
  const [columns, setColumns] = useState(getColumns({ textEllipsis }))

  const onTextEllipsisChange = useCallback((value) => {
    setTextEllipsis(value)
    setColumns(getColumns({ textEllipsis: value }))
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={textEllipsis}
          onChange={onTextEllipsisChange}
        >
          Show text ellipsis on description column.
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

A value for aligning text on the vertical axis inside <ReactDataGrid /> cells.
Valid values are: "top", "center" (or "middle") and "bottom". By default, cell contents are "middle"-aligned.
If column.headerVerticalAlign is not specified, column.textVerticalAlign will also be used for vertically aligning content in the column header.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', header: 'Name', defaultFlex: 1, textVerticalAlign: 'top' },
  { name: 'city', header: 'City', defaultFlex: 1, textVerticalAlign: 'middle' },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1, textVerticalAlign: 'bottom' }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Column headers with none, top, middle and bottom vertical alignment
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        rowHeight={100}
        headerHeight={100}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

Specifies the type of the column data. For numeric columns, specify columns.type="number" for sorting in numeric order, instead of using string sort order. If not specified, the<ReactDataGrid /> will assume string content and will use String.prototype.localeCompare to compare values, which is not what you want for numbers.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 }
]

const gridStyle = {
  maxHeight: 400
}

export default () => <ReactDataGrid
  idProperty="id"
  columns={columns}
  dataSource={people}
  style={gridStyle}
/>

Bool
default: undefined

Specifies whether the content from the specific column can be selected by the user.
Overrides columnUserSelect.
For configuring text-selection in the column header, use columns.headerUserSelect.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', header: 'Name - test cell selection on this column', defaultFlex: 1, minWidth: 250, },
  { name: 'age', minWidth: 250, defaultFlex: 1, header: 'Content can always be selected' }
]

const App = () => {
  const [columnUserSelect, setColumnUserSelect] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={columnUserSelect} onChange={setColumnUserSelect}>
          Enable browser text selection in cells
        </CheckBox>
      </div>
      <p>The contents inside the 'name' column are always selectable, since it's configured with userSelect: true</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnUserSelect={columnUserSelect}
        columns={columns}
        dataSource={people}
        sortable={false}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Determines whether a column is visible or not. Set this to false if you want to hide a column. If not specified (so column.visible is undefined), the column will be visible.
This is a controlled prop. For the uncontrolled version, use defaultVisible.
If you use the controlled prop, make sure you update the column visible prop value when onColumnVisibleChange({ column, visible }) is triggered.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = ({ visible }) => {
  return [
    { name: 'id', header: 'Id', type: 'number', defaultWidth: 70, visible },
    { name: 'firstName', header: 'Name', defaultFlex: 1 },
    { name: 'email', header: 'Email', defaultFlex: 1 },
    { name: 'country', header: 'Country', defaultFlex: 1 },
    { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 }
  ]
}

const App = () => {
  const [visible, setVisible] = useState(false)
  const [columns, setColumns] = useState(getColumns({ visible }))

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={visible}
          onChange={visible => {
            setVisible(visible)
            setColumns(getColumns({ visible }))
          }}
        >
          Show Id column
        </CheckBox>
      </div>
      <ReactDataGrid
        key={visible}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

Configures the column size.
This is a controlled prop, so when the user resizes the column, you have to make sure you listen to onColumnResize and update the column width accordingly.
You may want to use the uncontrolled defaultWidth to specify the column size for a fixed column, so it updates the column width on resize without any other configuration.
Columns can also be flexible - see column.flex.
Minimum and maximum dimensions can be specified via column.minWidth and column.maxWidth.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const defaultColumns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultFlex: 1 },
  { name: 'firstName', header: 'Name', width: 120 },
  { name: 'country', header: 'Country', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', width: 80 }
]

const App = () => {
  const [columns, setColumns] = useState(defaultColumns)

  const onColumnResize = useCallback(({ column, flex, width }) => {
    const newColumns = columns.map(c => {
      if (c.name === column.name) {
        c = Object.assign({}, c, { width, flex })
      }
      return c
    })
  }, [columns])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        First and last columns with fixed width
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        onColumnResize={onColumnResize}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Controls whether native browser text selection is active or not. Since this prop defaults to false, browser text selection is disabled. Set this to true to enable text selection in the <ReactDataGrid />.
This can be overridden by columns.userSelect, at column-level.
For configuring text-selection in the <ReactDataGrid /> header, use columnHeaderUserSelect.
import React, { useState } from 'react'

import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', header: 'Name - try selecting text in cells', defaultFlex: 1, minWidth: 250, },
  { name: 'age', defaultFlex: 1, minWidth: 250, header: 'Cells in this col are always selectable - userSelect: true', userSelect: true }
]

const App = () => {
  const [columnUserSelect, setColumnUserSelect] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={columnUserSelect} onChange={setColumnUserSelect}>
          Enable browser text selection in cells
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnUserSelect={columnUserSelect}
        columns={columns}
        dataSource={people}
        sortable={false}
      />
    </div>
  );
}

export default () => <App />

Array|Promise|Fn()=>Promise
default: undefined

Specifies the source of data for <ReactDataGrid /> contents. The <ReactDataGrid /> supports both sync & async dataSource.
The simplest use-case is a synchronous dataSource, in the form of an array. The dataSource items (the objects in the array) are not constrained to a specific scheme, but they need to have a property which can be used as a unique identifier (most often, this is called "id"). When configuring the <ReactDataGrid />, this property should be specified in the idProperty . The properties in the dataSource items, although not constrained to a scheme, will generally match the configured columns.
Besides a plain array, the <ReactDataGrid /> supports async dataSource which can be specified as a Promise or a function returning a Promise. Again, the rules of immutability apply, so make sure you pass a reference to the same promise/function when you want to render the same-exact dataSource.
The promise (as specified by dataSource or as returned by the dataSource function) should be resolved with two possible value types:
  • an array - to be used as the data for the grid
  • an object with the data: Array and count: Number properties - this is generally useful when using remote data with pagination and the count represents the total number of records on the server (only a part of those are sent to the client via pagination).
Besides returning a Promise, dataSource as a function can also return an array, for synchronous dataSource that you want to have full control over (this function is passed info about sortInfo, skip and limit).
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 500, marginTop: 10 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, hedaer: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const loadData = ({ skip, limit, sortInfo }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination
        defaultLimit={15}
        defaultSkip={15}
        pageSizes={[10, 15, 30]}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />
You can read a bit more about the Using a dataSource and on using pagination in those specific pages.

Number[2]
default: undefined

This enables cell keyboard navigation in the <ReactDataGrid /> (as opposed to row keyboard navigation). For row navigation, see defaultActiveIndex or activeIndex.
This is an uncontrolled prop. For the controlled version, see activeCell.
When the user uses the keyboard to change the currently active<ReactDataGrid /> cell onActiveCellChange is triggered.
The value of the defaultActiveCell should be an array of length 2, the first value being the row index, while the second value is the column index of the activeCell.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 300 }
const defaultActiveCell = [4,1]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
]

const App = () => {
  const [enableKeyboardNavigation, setEnableKeyboardNavigation] = useState(true);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={enableKeyboardNavigation} onChange={setEnableKeyboardNavigation}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultActiveCell={defaultActiveCell}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Specifies the default active index for the <ReactDataGrid />. This is an uncontrolled prop. For the controlled version, see activeIndex.
When there is an active row, you can use keyboard interaction to change the active row via arrow up/down, page up/down and home/end.
When navigating the <ReactDataGrid /> with keyboard navigation, as the active index is updated, the <ReactDataGrid /> is automatically scrolled to show the currently active row in the viewport.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 500 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', minWidth: 100, defaultFlex: 1, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultActiveIndex={1}
        enableKeyboardNavigation={true}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Specifies a default value for cell selection. This is an uncontrolled prop. For the controlled version, see cellSelection.
The cell selection value is an object with keys being strings - each string representing a cell. Values should be the boolean true. The string for each cell is the value of the idProperty for that row, followed by a comma and by the name/id of corresponding column: <idProperty value>,<column id or name>: eg "id1,firstName".
The presence of this prop enables cell selection.
By default cell selection is multiple. If you want to enable single cell selection, specify multiSelect=false.
You can use the little square at the bottom-right border of the active cell to drag and extend the current cell selection.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const defaultCellSelection = {"2,name": true, "2,city": true}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, resizable: false },
  { name: 'name', header: 'Name', defaultFlex: 1, sortable: false },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultWidth: 100, type: 'number' }
]

const App = () => {
  const [cellSelection, setCellSelection] = useState(defaultCellSelection)

  return (
    <div>
      <p>
        Selected cells: {cellSelection.length == 0 ? 'none' : JSON.stringify(cellSelection)}.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultCellSelection={defaultCellSelection}
        onCellSelectionChange={setCellSelection}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Specifies groups that should render as collapsed by default. This is an uncontrolled prop. For the controlled version, see collapsedGroups
The keys of the object should be the "paths" to collapsed groups. For example, if records are first grouped by country, and "uk" is a country shared by many records, and then grouped by city, with "London" being the city value for many items, then "uk/London" (a concatenation of the two, separated by groupPathSeparator) is the key to be used in the collapsedGroups object in order to render "London" people as collapsed.
As mentioned, the concatenation is done by using groupPathSeparator.
When the user interacts with the groups and expands/collapses a group, onGroupCollapseChange is triggered (whether controlled collapsedGroups or uncontrolled defaultCollapsedGroups is used).
defaultCollapsedGroups=true means all groups are collapsed.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

const defaultCollapsedGroups = { 'uk/London': true, 'usa': true }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultWidth: 140, header: 'Country' },
  { name: 'city', defaultWidth: 140, header: 'City' },
  { name: 'email', defaultWidth: 140, defaultFlex: 1, header: 'Email' }
]

const App = () => {
  const [groupBy, setGroupBy] = useState(['country','city'])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultCollapsedGroups={defaultCollapsedGroups}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

This property is only used when defaultExpandedRows=true!
Specifies which rows in the <ReactDataGrid /> should be rendered collapsed by default, when all other rows are expanded (defaultExpandedRows=true). This is an uncontrolled prop. For the controlled version, see collapsedRows
For row expand to be meaningful, you have to specify renderRowDetails in order to render the row details on expand.
The keys in this object should be the ids of the collapsed rows, while the value for each key should be true.
Use onExpandedRowsChange to be notified when the expanded/collapsed rows change.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const renderRowDetails = ({ data }) => {
  return <div style={{ padding: 20}}>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const defaultCollapsedRows = { 1: true, 2: true }

const App = () => {
  const [expandedRows, setExpandedRows] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => setExpandedRows(true)} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => setExpandedRows({})}>
          Collapse all
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        expandedRows={expandedRows}
        defaultCollapsedRows={defaultCollapsedRows}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Specifies groups that should render as expanded by default. This is an uncontrolled prop. For the controlled version, see expandedGroups
The keys of the object should be the "paths" to collapsed groups. For example, if records are first grouped by country, and "uk" is a country shared by many records, and then grouped by city, with "London" being the city value for many items, then "uk/London" (a concatenation of the two, separated by groupPathSeparator) is the key to be used in the expandedGroups object in order to render "London" people as expanded.
As mentioned, the concatenation is done by using groupPathSeparator.
When the user interacts with the groups and expands/collapses a group, onGroupCollapseChange is triggered (whether controlled expandedGroups or uncontrolled defaultExpandedGroups is used).
defaultExpandedGroups=true means all groups are expanded.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

const defaultExpandedGroups = { 'uk/London': true, 'usa': true }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultWidth: 140, header: 'Country' },
  { name: 'city', defaultWidth: 140, header: 'City' },
  { name: 'email', defaultWidth: 140, defaultFlex: 1, header: 'Email' }
]

const App = () => {
  const [groupBy, setGroupBy] = useState(['country','city'])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultExpandedGroups={defaultExpandedGroups}
        defaultCollapsedGroups={true}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Specifies which nodes in the <ReactDataGrid /> should be rendered expanded by default. This is an uncontrolled prop. For the controlled version, see expandedNodes
The keys in this object should be the ids of the expanded nodes, while the value for each key should be true.
Use onExpandedNodesChange to be notified when the expanded/collapsed nodes change.
Specifying a node as expanded does not render its parent as expanded. For example, in the snippet below, the node with the id '3/1' is specified as expanded, but its parent is not.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb'
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb'
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const defaultExpandedNodes = { 1: true, 2: true, '3/1': true }

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const App = () => {
  return (
    <div>
      <p>
        Specifying a node as expanded does not render its parent as expended.
      </p>
      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Object|Boolean
default: undefined

Specifies which rows in the <ReactDataGrid /> should be rendered expanded by default. This is an uncontrolled prop. For the controlled version, see expandedRows
For row expand to be meaningful, you have to specify renderRowDetails in order to render the row details on expand.
The keys in this object should be the ids of the expanded rows, while the value for each key should be true.
If you only want one row to be expanded at a time, specify multiRowExpand=false.
Specifying true renders all rows as expanded. In this case, you can use defaultCollapsedRows to indicate which rows (if any) should be rendered as collapsed by default.
Use onExpandedRowsChange to be notified when the expanded/collapsed rows change.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const renderRowDetails = ({ data }) => {
  return <div style={{ padding: 20}}>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const expandedRows = { 2: true, 1: true }

const App = () => {
  return (
    <div>
      <p>
        The second and third row is expanded by default.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={expandedRows}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Array[Object]
default: undefined

Specifies a default filter value for the <ReactDataGrid />. When this is specified, unless enableFiltering is false, the <ReactDataGrid /> becomes filterable.
This is an uncontrolled prop. For the controlled version, see filterValue.
If you want to intercept filter value changes, use onFilterValueChange.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, maxWidth: 100, type: 'number' },
  { name: 'name', defaultFlex: 1, minWidth: 200, maxWidth: 300, header: 'Name' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' },
  { name: 'country', defaultFlex: 1, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
      <p>Delete the filters if you want to show all data. You can click the configure icon and then "Clear All"</p>
    </div>
  );
}

export default () => <App />

String[]
default: undefined

Specifies a property or a list of properties to use for initially grouping rows together.
This is an uncontrolled prop. It's easier to get started by using this prop rather than the controlled groupBy since you don't have to hook onGroupByChange callback prop and update the <ReactDataGrid /> when there are grouping changes. You can also use drag-and-drop to reorder group by columns. Or you can click the remove icon to ungroup by a specific column.
By default, columns used for grouping are not displayed in the<ReactDataGrid />. See hideGroupByColumns if you want to change that.
In the example below, try dragging the age column header to the grouping toolbar in the <ReactDataGrid /> and see grouping being updated.
To specify a custom grouping value for a column, use the column.groupToString function prop.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'country', defaultFlex: 1, header: 'Country' },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={['country']}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: 50

The default page size for the <ReactDataGrid />, when pagination is enabled.
This is an uncontrolled prop. For the controlled version, see limit.
You can use onLimitChange to get notified when the user changes the current page size from the pagination toolbar ComboBox.
The pagination toolbar has a ComboBox displaying a choice of page-sizes. The options in the ComboBox can be configured via pageSizes.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 500, marginTop: 10 }

const loadData = ({ skip, limit }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const App = () => {
  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <ReactDataGrid
        sortable={false}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination
        dataSource={dataSource}
        defaultLimit={100}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Specifies whether the load mask should be initially visible or not.
This is an uncontrolled prop. For the controlled alternative, use loading.
When pagination or remote dataSource is used, the uncontrolled defaultLoading is used by the <ReactDataGrid />. If you are using the controlled loading, you need to make sure the loading mask is displayed while fetching remote data.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'age', header: 'Age' }
]

const App = () => {
  const [loading, setLoading] = useState(true)
  const [dataSource, setDataSource] = useState([])

  // Let's make this intentionally slow, in order to see the loading better
  const mockTimeConsumingLoad = useCallback(() => {
    const data = new Promise((resolve) => {
      setTimeout(() => {
        resolve([
          { name: 'John Grayner', age: 35, id: 0 },
          { name: 'Mary Stones', age: 25, id: 1 },
          { name: 'Robert Fil', age: 27, id: 2 },
          { name: 'Bob Margin', age: 17, id: 3 },
          { name: 'Hillary Wilson', age: 53, id: 4 },
          { name: 'Franklin Richardson', age: 37, id: 5 }
        ])
      }, 2000)
    })

    setDataSource(data)
  }, [])

  return (
    <div>
      <p>
        <Button onClick={mockTimeConsumingLoad}>
          Start long loading...
        </Button>
      </p>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={loading}
          onChange={setLoading}
        >
          Default loading
        </CheckBox>
      </div>
      <ReactDataGrid
        style={{ marginTop: 10, minHeight: 300 }}
        idProperty="id"
        columns={columns}
        dataSource={dataSource}
        defaultLoading={loading}
      />
    </div>
  );
}

export default () => <App />

String|Number|Object
default: undefined

Specifies the default selected row (or rows) in the <ReactDataGrid />. This is an uncontrolled prop. For the controlled version, see selected.
For single row selection, pass a string or a number as the value of this prop. The value of the prop should be the id of the row you want to show as selected (see idProperty).
For multiple selection, use an object as the prop value - the keys should be the ids of all the rows you want to show as selected (see idProperty), while the values should be any truthy values.
When the user interacts with the <ReactDataGrid /> and changes the selection, onSelectionChange is called so you get a chance to update the value for the selected accordingly.
Multiple selection can also be used with a checkbox column. Specify checkboxColumn and a checkbox column will be displayed as the first column of the <ReactDataGrid /> and will be used for multiple selection.
When checkboxColumn is used, checkboxOnlyRowSelect might also be very handy in order to only update row selection when the selection checkboxes are toggled.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const defaultSelected = { 1: true, 2: true }

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  const [selected, setSelected] = useState(null);

  const onSelectionChange = useCallback(({ selected: selectedMap }) => {
    setSelected(selectedMap)
  }, [])

  return (
    <div>
      <p>
        Selected rows: {selected === null ? JSON.stringify(Object.keys(defaultSelected)) : JSON.stringify(Object.keys(selected))}.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultSelected={defaultSelected}
        onSelectionChange={onSelectionChange}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: 0

The default skip value for the <ReactDataGrid />, when pagination is enabled.
This is an uncontrolled prop. For the controlled version, see skip.
When using this controlled prop, make sure you update its value when onSkipChange is triggered, so the dataSource (most often, a function when the <ReactDataGrid /> has remote pagination) can be reloaded with the correct skip value.
import React, { useState, useCallback } from 'react'

import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 500, marginTop: 10 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const loadData = ({ skip, limit, sortInfo }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then((data) => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination
        defaultLimit={15}
        defaultSkip={45}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Object|Object[]
default: undefined

Specifies the default sort order for the <ReactDataGrid />. This is an uncontrolled prop. For the controlled version, see sortInfo.
When uncontrolled sorting is used, the <ReactDataGrid /> will sort the dataSource internally, so no need to pass a sorted dataSource.
When an object is specified, the sorting is single.
For multiple sorting, specify an array of objects, in the correct order.
For more details on how to use sortInfo, see Controlled and uncontrolled sorting.
Basically, for controlled sorting, you have to perform the sorting of the dataSource yourself, be it local or remote data source.
Uncontrolled sorting via defaultSortInfo is easier to use as you don't have to worry about sorting yourself. In case of remote dataSource (generally a function returning a Promise), you need to make sure you send the correct sorting params to the server so as to sort the data server-side.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const defaultSortInfo = { name: 'age', dir: -1, type: 'number' }

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, sortable: false },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 }
]

const dataSource = [
  { name: 'Little Johnny', age: 8, id: 1 },
  { name: 'John Brown', age: 35, id: 2 },
  { name: 'Mary Stones', age: 35, id: 3 },
  { name: 'Robert Fil', age: 17, id: 4 },
  { name: 'Bob Margin', age: 17, id: 5 },
  { name: 'Hillary Wilson', age: 53, id: 6 },
  { name: 'Franklin Richardson', age: 37, id: 7 }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        defaultSortInfo={defaultSortInfo}
        columns={columns}
        dataSource={dataSource}
        style={gridStyle}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Used in combination with remote dataSource and defaultSelected.
Specifies which <ReactDataGrid /> rows should be rendered as unselected. When selected=true (or defaultSelected=true) , all items but those specified by this prop should be selected.
The defaultUnselected object should be keyed using item ids, as specified by their idProperty.
This is an uncontrolled prop. For the controlled version, see unselected.
You can use onSelectionChange({ selected, unselected }) to listen to changes in the selection.
Most often, this is also used in combination withcheckboxColumn=true.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 400, marginTop: 10 }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 70, header: 'Id', defualtVisible: false },
  { name: 'firstName', defaultWidth: 135, header: 'First Name' },
  { name: 'lastName', defaultWidth: 135, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultWidth: 135, header: 'Email' }
]

const loadData = ({ skip, limit }) => {
  return fetch(DATASET_URL).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [checkboxOnlyRowSelect, setCheckboxOnlyRowSelect] = useState(true);
  const [selected, setSelected] = useState(true);
  const [unselected, setUnselected] = useState({ 1: true, 3: true });

  const dataSource = useCallback(loadData, [])

  const onSelectionChange = useCallback(({ selected, unselected }) => {
    setSelected(selected);
    setUnselected(unselected)
  }, [])

  return (
    <div>
      <p>
        Unselected rows: {unselected && Object.keys(unselected).length ? JSON.stringify(Object.keys(unselected)) : (selected === true ? 'none' : 'too many')}.
      </p>
      <div>
        <CheckBox
          checked={checkboxOnlyRowSelect}
          onChange={setCheckboxOnlyRowSelect}
        >
          Update row select using checkbox clicks only
        </CheckBox>
      </div>
      <ReactDataGrid
        key={'grid-' + checkboxOnlyRowSelect}
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        columns={columns}
        checkboxOnlyRowSelect={checkboxOnlyRowSelect}
        pagination
        selected={selected}
        defaultUnselected={unselected}
        onSelectionChange={onSelectionChange}
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Controls visibility of the grouping toolbar displayed when groupBy (or defaultGroupBy) is specified.
By default, it is diplayed when grouping is specified.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  const [disableGroupByToolbar, toggle] = useState(false);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={!disableGroupByToolbar}
          onChange={checked=>toggle(!checked)}
        >
          Show groupBy toolbar
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        columns={columns}
        dataSource={people}
        defaultGroupBy={['country']}
        disableGroupByToolbar={disableGroupByToolbar}
      />
    </div>
  );
}
export default () => <App />

Bool|Function(editValue, cellProps)
default: false

Specifies whether the <ReactDataGrid /> should have inline edit enabled or not.
If the value is a function, it can either return a boolean value, or a Promise. In case a Promise is returned, if it is rejected or resolved with false, the cell is not editable. If the returned Promise is resolved with true, the cell is editable.
Is overriden by columns.editable.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, editable: () => false, header: 'Name' },
  { name: 'country', header: 'Country', defaultFlex: 1,
    editable: (editValue) => {
      return Promise.resolve(editValue !== 'uk')
    },
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  const [dataSource, setDataSource] = useState(people)
  const [editable, setEditable] = useState(true)

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data)
  }, [dataSource])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={editable}
          onChange={setEditable}
        >
          Enable inline edit
        </CheckBox>
      </div>
      <p>Name column not editable.</p>
      <p>!!! Cells with "uk" are not editable !!!
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable={editable}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

String
default: "dblclick"

Defines on which event the edit should start. Defaults to "dblclick". Possible values are "click" and "dblclick"
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, editable: () => false, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  const [dataSource, setDataSource] = useState(people)
  const [editOnSingleClick, setEditOnSingleClick] = useState(true)

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data)
  }, [dataSource])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={editOnSingleClick}
          onChange={setEditOnSingleClick}
        >
          Edit on click (not double click)
        </CheckBox>
      </div>
      <p>editStartEvent can have one of those two values: "click" or "dblclick"
      </p>
      <p>Currently starting the edit on {editOnSingleClick? 'click':'dblclick'}
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        editStartEvent={editOnSingleClick ? "click" : "dblclick"}
        onEditComplete={onEditComplete}
        editable={true}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

React.Node|Fn()
default: "No records available"

When the <ReactDataGrid /> has no records,emptyText), will be displayed centered inside the <ReactDataGrid /> viewport to provide feedback to the user.
It can be a string, a React.Node (so any valid jsx) or a function returning anything renderable (React.Node).
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const emptyText = <b style={{
  padding: 8,
  border: '1px solid #7986cb',
  color: '#ef9a9a',
  borderRadius: 4
}}>No contents here !!!</b>

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, minWidth: 80, header: 'Name' },
  { name: 'country', defaultFlex: 1, minWidth: 80, header: 'Country' },
  { name: 'city', defaultFlex: 1, minWidth: 80, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        emptyText={emptyText}
        columns={columns}
        dataSource={[]}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

When true, makes the <ReactDataGrid /> filterable if defaultFilterValue or filterValue is specified.
When false, it will make the <ReactDataGrid /> unfilterable (even if defaultFilterValue or filterValue have been specified).
This is generally useful when you want to toggle filtering for an already filterable <ReactDataGrid />.
This is a controlled prop.
When the user clicks "Show filtering row"/"Hide filtering row" in the column header menu, it will trigger onEnableFilteringChange to allow the<ReactDataGrid /> to respond to the change.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1,
    hedaer: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', hedear: 'Age' }
]

const App = () => {
  const [enableFiltering, setEnableFiltering] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableFiltering}
          onChange={setEnableFiltering}
        >
          Enable filtering
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={filterValue}
        enableFiltering={enableFiltering}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Enables keyboard navigation - when keyboard navigation is enabled, clicking on a row makes it the active row. After the <ReactDataGrid /> is focused and there is an active row, arrow up/down, page up/down and home/end can be used to change the current activeIndex.
A default active index can be specified via defaultActiveIndex or activeIndex.
For cell-level navigation, see activeCell.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'city', minWidth: 100, defaultFlex: 1, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
]

const App = () => {
  const [enableKeyboardNavigation, setEnableKeyboardNavigation] = useState(true)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={enableKeyboardNavigation} onChange={setEnableKeyboardNavigation}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultActiveIndex={2}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Enables expanded rows in the <ReactDataGrid />.
When this prop is not explicitly specified, the <ReactDataGrid /> is expandable if one of the following is specified:expandedRows, defaultExpandedRows, renderRowDetails).
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import Button from '@inovua/reactdatagrid-community/packages/Button'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const defaultExpandedRows = { 1: true }

const renderRowDetails = ({ data, toggleRowExpand }) => {
  return <div style={{ padding: 20}}>
    <h3><Button onClick={toggleRowExpand}>Collapse row</Button></h3>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const App = () => {
  const [enableRowExpand, setEnableRowExpand] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableRowExpand}
          onChange={setEnableRowExpand}
        >
          Enable row expand
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        renderRowDetails={renderRowDetails}
        enableRowExpand={enableRowExpand}
        style={gridStyle}
        rowExpandHeight={400}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Controls whether single row selection is enabled or not.
In order to enable row selection, either use enableSelection=true or use the controlled selected prop or the uncontrolled defaultSelected prop.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const App = () => {
  const [selected, setSelected] = useState(null);
  const [enableSelection, setEnableSelection] = useState(true);

  const onSelectionChange = useCallback(({ selected }) => {
    setSelected(selected)
  })

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableSelection}
          onChange={setEnableSelection}
        >
          Enable selection
        </CheckBox>
      </div>
      <p>
        Selected row id: {selected === null ? 'none' : JSON.stringify(selected)}.
      </p>
      <ReactDataGrid
        idProperty="id"
        enableSelection={enableSelection}
        onSelectionChange={onSelectionChange}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({data})
default: undefined

If specified, it's called for each row, with the corresponding data object. Can be used to expand a certain column on the current row to occupy the rest of the row.
Should return the id of the column you want to expand on the current row, or undefined if none
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  {
    id: 'desc',
    header: 'Description',
    defaultFlex: 2,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  },
  { name: 'firstName', header: 'Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultWidth: 100 },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 },

]

const expandColumn = ({ data }) => {
  if (data.country === 'uk') {
    return 'desc'
  }
}

const App = () => {
  return (
    <ReactDataGrid
      idProperty="id"
      expandColumn={expandColumn}
      style={gridStyle}
      columns={columns}
      dataSource={people}
    />
  );
}

export default () => <App />

Object | true
default: undefined

Specifies groups that should render as expanded. This is a controlled prop. For the uncontrolled version, see defaultExpandedGroups.
Should be used together with collapsedGroups/defaultCollapsedGroups
The keys of the object should be the "paths" to expanded groups. For example, if records are first grouped by country, and "uk" is a country shared by many records, and then grouped by city, with "London" being the city value for many items, then "uk/London" (a concatenation of the two, separated by groupPathSeparator) is the key to be used in the expandedGroups object in order to render "London" people as expanded.
As mentioned, the concatenation is done by using groupPathSeparator.
If true, it means all groups are expanded, except those specified by collapsedGroups
Just one of expandedGroups and collapsedGroups should be true at any given time.
When the user interacts with the groups and expands/collapses a group, onGroupCollapseChange is triggered (whether controlled collapsedGroups or uncontrolled defaultCollapsedGroups is used).
When using the controlled expandedGroups, make sure you update the expandedGroups value when onGroupCollapseChange is triggered, but also collapsedGroups
collapsedGroups and expandedGroups should be both either controlled or uncontrolled.
expandedGroups=true means all groups are expanded (except those explicitly specified by collapsedGroups).
collapsedGroups=true means all groups are collapsed, except those explicitly specified in expandedGroups
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultWidth: 140, header: 'Country' },
  { name: 'city', defaultWidth: 140, header: 'City' },
  { name: 'email', defaultWidth: 140, defaultFlex: 1, header: 'Email' }
]

const App = () => {
  const [groupBy, setGroupBy] = useState(['country','city'])
  const [expandedGroups,  setExpandedGroups] = useState({ 'uk/London': true, 'usa': true })
  const [collapsedGroups,setCollapsedGroups ] = useState(true)

  const onGroupCollapseChange = useCallback((collapsedGroups, expandedGroups) => {
    setCollapsedGroups(collapsedGroups)
    setExpandedGroups(expandedGroups)
  }, [])

  return (
    <div>
      <p>
        Expanded groups: {JSON.stringify(Object.keys(expandedGroups))}.
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        collapsedGroups={collapsedGroups}
        expandedGroups={expandedGroups}
        onGroupCollapseChange={onGroupCollapseChange}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Specifies which nodes in the <ReactDataGrid /> (with tree functionality) should be rendered expanded. This is a controlled prop. For the uncontrolled version, see defaultExpandedNodes
The keys in this object should be the ids of the expanded nodes, while the value for each key should be true.
Nested nodes should have an id but it only needs to be unique at their nesting level. The <ReactDataGrid /> will assign a unique id (see idProperty) to all nodes based on the path from the root node to the respective node. This id value is built by joining all the parent ids using the / character (as defined by nodePathSeparator prop). So, for example, expandedNodes could look like this for a grid: expandedNodes={ 1: true, 3: true, '3/1': true', '3/2/1': true }.
Use onExpandedNodesChange to be notified when the expanded/collapsed nodes change. When using this controlled prop, make sure you update it's value when onExpandedNodesChange is called.
Specifying a node as expanded does not render its parent as expanded. For example, in the snippet below, the node with the id '3/1' is specified as expanded, but its parent is not.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb'
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb'
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'size', header: 'Size', defaultWidth: 120 }
]

const App = () => {
  const [expandedNodes, setExpandedNodes] = useState({ 1: true, 2: true, '3/1': true });

  const onExpandedNodesChange = useCallback(({ expandedNodes }) => {
    setExpandedNodes(expandedNodes)
  }, [])

  return (
    <div>
      <p>
        Expanded nodes: {expandedNodes == null ? 'none' : JSON.stringify(expandedNodes, null, 2)}.
      </p>
      <ReactDataGrid
        treeColumn="name"
        expandedNodes={expandedNodes}
        onExpandedNodesChange={onExpandedNodesChange}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Object|Boolean
default: undefined

Specifies which rows in the <ReactDataGrid /> should be rendered expanded. This is a controlled prop. For the uncontrolled version, see defaultExpandedRows
For row expand to be meaningful, you have to specify renderRowDetails in order to render the row details on expand.
The keys in this object should be the ids of the expanded rows, while the value for each key should be true.
If you only want one row to be expanded at a time, specify multiRowExpand=false.
Specifying true renders all rows as expanded. In this case, you can use collapsedRows to indicate which rows (if any) should be rendered as collapsed.
Use onExpandedRowsChange to be notified when the expanded/collapsed rows change. When using this controlled prop, make sure you update it's value when onExpandedRowsChange is called.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const renderRowDetails = ({ data }) => {
  return <div style={{ padding: 20}}>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const App = () => {
  const [expandedRows, setExpandedRows] = useState({ 1: true, 2: true });
  const [collapsedRows, setCollapsedRows] = useState(null);

  const onExpandedRowsChange = useCallback(({ expandedRows, collapsedRows }) => {
    setExpandedRows(expandedRows);
    setCollapsedRows(collapsedRows);
  }, [])

  return (
    <div>
      <div>
        <Button onClick={() => setExpandedRows(true)} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => setExpandedRows({})}>
          Collapse all
        </Button>
      </div>
      <p>
        Expanded rows: {expandedRows == null ? 'none' : JSON.stringify(expandedRows, null, 2)}.
      </p>
      {expandedRows === true ? <p>
        Collapsed rows: {collapsedRows == null ? 'none' : JSON.stringify(collapsedRows, null, 2)}.
      </p> : null}
      <ReactDataGrid
        idProperty="id"
        expandedRows={expandedRows}
        collapsedRows={collapsedRows}
        onExpandedRowsChange={onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Specifies whether the group title should expand to occupy all available space to the right or not, when there are locked columns. Defaults to false.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 600 }

const renderGroupTitle = (valueParam, { data }) => {
  const { value, name, fieldPath } = data
  if (name === 'country') {
    return 'This is the current country for the group:' + value +'.'
  }
  if (name === 'age') {
    return 'Aged: ' + value +'.'
  }

  return value
}

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80,  header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name', groupBy: false, defaultLocked: true },
  { name: 'country', defaultFlex: 1, defaultLocked: true, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' },
  { name: 'email', defaultFlex: 1, defaultLocked: 'end', header: 'Email' },
]

const App = () => {
  const [defaultGroupBy, setDefaultGroupBy] = useState(['country'])
  const [expandGroupTitle, setExpandGroupTitle] = useState(false)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={expandGroupTitle}
          onChange={setExpandGroupTitle}
        >
          Expand group title
        </CheckBox>
      </div>
      <ReactDataGrid
        key={'grid-' + expandGroupTitle}
        idProperty="id"
        style={gridStyle}
        renderGroupTitle={renderGroupTitle}
        expandGroupTitle={expandGroupTitle}
        defaultGroupBy={defaultGroupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

This prop specifies all available filter types and their operators.
Here's a list of the types the <ReactDataGrid /> currently supports for filtering:
  • "string" - string/text filter. The following operators are supported:
    • "contains" - contains. Will filter the dataSource to only include items that for the current column have a value that contains the filter value.
    • "notContains" - not contains. Will filter the dataSource to only include items that for the current column have a value that does not contain the filter value.
    • "eq" - equals. Will filter the dataSource to only include items that for the current column have a value equal to the filter value.
    • "neq" - not equals. Will filter the dataSource to only include items that for the current column have a value not equal to the filter value.
    • "empty" - empty. Will filter the dataSource to only include items that for the current column have an empty value.
    • "notEmpty" - not empty. Will filter the dataSource to only include items that for the current column have a non empty value.
    • "startsWith" - starts with. Will filter the dataSource to only include items that for the current column have a value that starts with the filter value.
    • "endsWith" - ends with. Will filter the dataSource to only include items that for the current column have a value that ends with the filter value.
  • "number" - numeric filter. The following operators are supported:
    • "eq" - equals. Will filter the dataSource to only include items that for the current column have a value equal to the filter value.
    • "neq" - not equals. Will filter the dataSource to only include items that for the current column have a value not equal to the filter value.
    • "gt" - greater than. Will filter the dataSource to only include items that for the current column have a value greater than the filter value.
    • "gte" - greater than or equal. Will filter the dataSource to only include items that for the current column have a value greater than or equal to the filter value.
    • "lt" - less than. Will filter the dataSource to only include items that for the current column have a value less than the filter value.
    • "lte" - less than or equal. Will filter the dataSource to only include items that for the current column have a value less than or equal to the filter value.
  • "boolean" - boolean filter. The following operators are supported:
    • "eq" - equals. Will filter the dataSource to only include items that for the current column have a value equal to the filter value.
    • "neq" - not equals. Will filter the dataSource to only include items that for the current column have a value not equal to the filter value.
You can specify one of the above types for each item in the filterValue array. Make sure you specify an operator supported by the filter type of your choice.
You can specify other filter types and operators as well. The above are just the default supported filter types & operators, which can either be enhanced or replaced altogether.
Basically, the default filterTypes is just an object with keys being the name of the filter types and values being object describing the filter type.
ReactDataGrid.defaultProps.filterTypes = {
  string: {
    type: 'string',
    emptyValue: '',
    operators: [
      {
        'contains',
        fn: ({ value, filterValue, data }) => {
          return !filterValue ?
            true :
            value.indexOf(filterValue) != -1;
        }
      },
      {
        name: 'eq', fn: ({ value, filterValue }) => value===filterValue
      },
      ... other operators
    ]
  },
  boolean: {
    type: 'boolean',
    operators: [...]
  }
  ... other filter types
}
The above is basically part of the filterTypes default prop value. You can either enhance the <ReactDataGrid /> default props or pass another totally different filterTypes prop to get the desired filtering behavior.
For example, adding a filter type for date would look like the following:
ReactDataGrid.defaultProps.filterTypes.date = {
  type: 'date',
  emptyValue: '',
  operators: [
    {
      name: 'lt',
      fn: ({ value, filterValue, data }) => {
        return !filterValue ?
          true :
          value < filterValue
      }
    },
    {
      name: 'eq', fn: ({ value, filterValue }) => value === filterValue
    },
    ... other operators
  ]
}
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterTypes = Object.assign({}, ReactDataGrid.defaultProps.filterTypes, {
  country: {
    name: 'country',
    emptyValue: null,
    operators: [
      {
        name: 'europe',
        fn: ({ value, filterValue, data }) => {
          const isInEurope = value != 'usa' && value != 'ca'

          return filterValue ?
            isInEurope :
            !isInEurope
        }
      }
    ]
  }
});

const filterValue = [
  { name: 'country', operator: 'europe', type: 'country', value: true },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, maxWidth: 100, type: 'number' },
  { name: 'name', defaultFlex: 1, maxWidth: 200, header: 'Name' },
  { name: 'country',
    header: 'Country',
    defaultFlex: 1,
    filterEditor: 'bool',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ value, filterValue, data })
default: undefined

If the filter value for a column is === to the emptyValue for the current filterType, the filtering function is skipped and no longer called (so all items pass the filter)
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterTypes = Object.assign({}, ReactDataGrid.defaultProps.filterTypes, {
  country: {
    name: 'country',
    emptyValue: null,
    operators: [
      {
        name: 'europe',
        fn: ({ value, filterValue, data }) => {
          const isInEurope = value != 'usa' && value != 'ca'

          return filterValue ?
            isInEurope :
            !isInEurope
        }
      }
    ]
  }
});

filterValue = [
  { name: 'country', operator: 'europe', type: 'country', value: null },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country',
    header: 'Country',
    flex: 1,
    filterEditor: 'bool',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
];

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}
export default () => <App />

Array
default: undefined

Every filter type should support an array of operators.
For example, the boolean filters have the operators array equal to the following:
[
  {
    name: 'eq',
    fn: ({ value, filterValue, data }) => {
      return filterValue != null ? filterValue === value : true;
    }
  },
  {
    name: 'neq',
    fn: ({ value, filterValue, data }) => {
      return filterValue != null ? filterValue !== value : true;
    }
  }
]
See operators.fn for details on the filtering function.

Fn({ value, filterValue, data })
default: undefined

Controls which data items from the dataSource pass the filtering.
The function is called with an object, that has value (the cell value for the current column), filterValue (the value in the filter) and data (the current row data object) as keys.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterTypes = Object.assign({}, ReactDataGrid.defaultProps.filterTypes, {
  country: {
    name: 'country',
    operators: [
      {
        name: 'europe',
        fn: ({ value, filterValue, data }) => {
          if (filterValue == null) {
            return true
          }
          const isInEurope = value != 'usa' && value != 'ca'

          return filterValue ?
            isInEurope :
            !isInEurope
        }
      }
    ]
  }
});

const defaultFilterValue = [
  { name: 'country', operator: 'europe', type: 'country', value: true },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, maxWidth: 200, header: 'Name' },
  { name: 'country',
    header: 'Country',
    defaultFlex: 1,
    filterEditor: 'bool',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={defaultFilterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ value, filterValue, data })
default: undefined

The name for the column operator
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const filterTypes = Object.assign({}, ReactDataGrid.defaultProps.filterTypes, {
  country: {
    name: 'country',
    emptyValue: null,
    operators: [
      {
        name: 'europe',
        fn: ({ value, filterValue, data }) => {
          const isInEurope = value != 'usa' && value != 'ca'

          return filterValue ?
            isInEurope :
            !isInEurope
        }
      }
    ]
  }
});

const filterValue = [
  { name: 'country', operator: 'europe', type: 'country', value: null },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country',
    header: 'Country',
    defaultFlex: 1,
    filterEditor: 'bool',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' }
];

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Array[Object]
default: undefined

Specifies a filter value for the <ReactDataGrid />. When this is specified, unless enableFiltering is false, the <ReactDataGrid /> becomes filterable.
When controlled filterValue is used, it's the user's responsibility to filter out the dataSource!!!
This is a controlled prop (so make sure you also specify onFilterValueChange). For the uncontrolled version, see defaultFilterValue.
The filterValue is an array that holds the filter value for each filterable column. The objects in this array should have the following properties:
  • name - the name (or id) of the column for which the current filter is applied.
  • type - the type of the filter to apply. Valid types for now are: string, bool (or its alias, boolean) and number. If you want to add more filter types, see filterTypes.
  • operator - the operator to use for filtering. It needs to be one of the operators supported by the specified filter type.
  • value - the actual value to be used for filtering.
  • emptyValue (optional) - can specify a value for which the filter will not apply. Overrides filterTypes.emptyValue.
  • fn({ value, filterValue, data}) (optional) - can specify a custom filtering function. Overrides filterTypes.operators.fn.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import filter from '@inovua/reactdatagrid-community/filter'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const defaultFilterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'age', defaultFlex: 1, type: 'number', header: 'Age' },
  { name: 'country', defaultFlex: 1, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' }
]


const App = () => {
  const initialData = useCallback(filter(people, defaultFilterValue), []);

  const [dataSource, setDataSource] = useState(initialData);
  const [filterValue, setFilterValue] = useState(defaultFilterValue);

  const onFilterValueChange = useCallback((filterValue) => {
    const data = filter(people, filterValue)

    setFilterValue(filterValue);
    setDataSource(data);
  }, [])

  return (
    <div>
      <p>
        Current filter value: {JSON.stringify(filterValue, null, 2)}
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onFilterValueChange={onFilterValueChange}
        filterValue={filterValue}
        columns={columns}
        dataSource={dataSource}
      />
      <p>Delete the filters if you want to show all data. You can click the configure icon and then "Clear All"</p>
    </div>
  );
}

export default () => <App />

default: undefined

Specifies the footer to be used for the <ReactDataGrid /> - see footer page for more examples.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 600, marginTop: 10 }

let cities;

const footerRows = [
  {
    render: {
      population: ({ summary }) => <div>Total population: <b>{summary}</b>.</div>
    }
  }
]

const summaryReducer = {
  initialValue: 0,
  reducer: (accumulator, item) => accumulator + (item.population || 0)
}

const columns = [
  { name: 'name', defaultFlex: 1, header: 'City', },
  { name: 'country', defaultFlex: 1, header: 'Country'},
  {
    name: 'population',
    type: 'number',
    defaultFlex: 1,
    header: 'Population'
  }
];

const App = () => {
  return (
    <div>
      <h3>The population column has a summary - shown in corresponding footer column.</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={cities}
        summaryReducer={summaryReducer}
        footerRows={footerRows}
      />
    </div>
  );
}

cities = [
  {
    id: 'ny',
    country: 'USA',
    name: 'New York City',
    population: 1000
  },
  {
    id: 'la',
    country: 'USA',
    name: 'Los Angeles',
    population: 150
  },
  {
    id: 'paris',
    country: 'France',
    name: 'Paris',
    population: 2000
  },
  {
    id: 'london',
    name: 'London',
    country: 'UK',
    population: 3000
  },
  {
    id: 'SF',
    name: 'San Francisco',
    country: 'USA',
    population: 3900
  },
  {
    id: 'ly',
    name: 'Lyon',
    country: 'France',
    population: 980
  },
  {
    id: 'ma',
    name: 'Manchester',
    country: 'UK',
    population: 2000
  }
]

export default () => <App />

Object|number|() => number
default: undefined

Specifies the colspan for a footer cell.
It can be an object, with keys corresponding to columns, while values can either be functions or number values.
Beside being an object, it can be a function - which will be used for all columns.
Supporting functions, either as part of objects, or directly as the value for the colspan gives you complete flexibility over the functionality.
When a function is used, it's called like this:
if (typeof colspan === 'function') {
  colspan = colspan(
    {
      column,
      columnIndex,
      row,
      rowIndex,
    },
    computedProps
  );
}
so you have access to both the column being rendered and any other additional props you might need
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 600, marginTop: 10 }

let cities;

const footerRows = [
  {
    render: {
      population: ({ summary }) => <div>Population min: {summary.min}</div>
    },
    country: <b>Nothing to render</b>
  },
  {
    render: {
      population: ({ summary }) => <div>Population max: {summary.max}</div>
    }
  },
  {
    render: {
      population: ({ summary }) => <div>Population average: {summary.avg}</div>
    }
  },

  {
    render: {
      name: (_, computedProps) => {
        return <div>Selected rows: <b>{computedProps.computedSelectedCount}</b></div>
      }
    },
    colspan: {
      name: (_, computedProps) => computedProps.visibleColumns.length
    },
    cellStyle: ({ column }, computedProps) => {
      if (column.name !== 'name'){
        return
      }

      const style = {
        paddingTop: 20,
        paddingBottom: 20
      }

      if (computedProps.computedSelectedCount) {
        style.background = '#ff5b5b'
        style.color = 'white'
      }

      return style
    }
  }
]

const summaryReducer = {
  initialValue: {
    min: Infinity,
    max: 0,
    avg: 0
  },
  reducer: (accumulator, item) => {
    if (item.population) {
      return {
        min: Math.min(accumulator.min, item.population),
        max: Math.max(accumulator.max, item.population),
        avg: accumulator.avg + item.population
      }
    }

    return accumulator
  },
  complete: (accumulator, arr) => {
    return Object.assign({}, accumulator, {
      avg: Math.round(accumulator.avg / arr.length),
    })
  }
}

const columns = [
  { name: 'name', defaultFlex: 1, header: 'City', hideable: false, draggable: false },
  { name: 'country', defaultFlex: 1, header: 'Country'},
  {
    name: 'population',
    type: 'number',
    defaultFlex: 1,
    groupBy: false,
    header: 'Population'
  }
]

const App = () => {
  return (
    <div>
      <h3>Footer with custom render and colspan</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        defaultGroupBy={['country']}
        columns={columns}
        dataSource={cities}
        summaryReducer={summaryReducer}
        footerRows={footerRows}
      />
    </div>
  );
}

cities = [
  {
    id: 'ny',
    country: 'USA',
    name: 'New York City',
    population: 1000
  },
  {
    id: 'la',
    country: 'USA',
    name: 'Los Angeles',
    population: 150
  },
  {
    id: 'paris',
    country: 'France',
    name: 'Paris',
    population: 2000
  },
  {
    id: 'london',
    name: 'London',
    country: 'UK',
    population: 3000
  },
  {
    id: 'SF',
    name: 'San Francisco',
    country: 'USA',
    population: 3900
  },
  {
    id: 'ly',
    name: 'Lyon',
    country: 'France',
    population: 980
  },
  {
    id: 'ma',
    name: 'Manchester',
    country: 'UK',
    population: 2000
  }
]

export default () => <App />

{[columnId]: ReactNode|() => ReactNode}|ReactNode|() => ReactNode
default: undefined

Specifies what content to render inside footer cells.
Can be an object with keys corresponding to columns, while values can be functions or ReactNode values. Using a function gives you the flexibility to decide what to render at run-time - for example, the first argument will have a summary property which will hold the value computed via the configured summaryReducer.
Called with two args:
render(
  {
    summary,
    row,
    rowIndex,
    column,
    columnIndex,
  },
  computedProps
);
so in the render function you have access to both column information and the computed props of the grid.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 600, marginTop: 10 }

let cities;

const footerRows = [
  {
    render: {
      name: <b>Nothing to render here</b>,
      population: ({ summary }) => <div>Total population: <b>{summary}</b>.</div>
    }
  }
]

const summaryReducer = {
  initialValue: 0,
  reducer: (accumulator, item) => accumulator + (item.population || 0)
}

const columns = [
  { name: 'name', defaultFlex: 1, header: 'City', },
  { name: 'country', defaultFlex: 1, header: 'Country'},
  {
    name: 'population',
    type: 'number',
    defaultFlex: 1,
    header: 'Population'
  }
]

const App = () => {
  return (
    <div>
      <h3>The population column has a summary - shown in corresponding footer column.</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={cities}
        summaryReducer={summaryReducer}
        footerRows={footerRows}
      />
    </div>
  );
}

cities = [
  {
    id: 'ny',
    country: 'USA',
    name: 'New York City',
    population: 1000
  },
  {
    id: 'la',
    country: 'USA',
    name: 'Los Angeles',
    population: 150
  },
  {
    id: 'paris',
    country: 'France',
    name: 'Paris',
    population: 2000
  },
  {
    id: 'london',
    name: 'London',
    country: 'UK',
    population: 3000
  },
  {
    id: 'SF',
    name: 'San Francisco',
    country: 'USA',
    population: 3900
  },
  {
    id: 'ly',
    name: 'Lyon',
    country: 'France',
    population: 980
  },
  {
    id: 'ma',
    name: 'Manchester',
    country: 'UK',
    population: 2000
  }
]

export default () => <App />

Bool
default: true

If this is true, the <ReactDataGrid /> will assign a unique id (see idProperty) to all nodes based on the path from the root node to the respective node. This id value is built by joining all the parent ids using the / character (as defined by nodePathSeparator prop). In this case, the ids of each node in the dataSource should only be unique among node siblings.
If this is false, all nodes in the tree should have unique ids (unique in all dataSource, not only unique sibling ids). In this case, the <ReactDataGrid /> does not modify the ids of nodes.

String[]
default: undefined

Specifies a property or a list of properties to use for grouping rows together.
This is a controlled prop. It's easier to get started by using defaultGroupBy since you don't have to hook onGroupByChange callback prop and update the <ReactDataGrid /> when there are grouping changes. You can also use drag-and-drop to reorder group by columns. Or you can click the remove icon to ungroup by a specific column.
By default, columns used for grouping are not displayed in the<ReactDataGrid />. See hideGroupByColumns if you want to change that.
When you have some locked columns, you might want to use expandGroupTitle=true to make sure the group title expands to occupy the whole available group row.
Also, you might find renderGroupTitle useful in order to customize what gets rendered as the title of a group.
To specify a custom grouping value for a column, use the column.groupToString function prop.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, groupBy: false, type: 'number', defaultWidth: 50 },
  { name: 'firstName', header: 'First Name', defaultWidth: 150 },
  { name: 'lastName', header: 'Last Name', defaultWidth: 150 },
  { name: 'email', header: 'Email', groupBy: false, defaultWidth: 150 },
  {
    name: 'permissionToCall',
    header: 'Permission to call',
    defaultWidth: 200,
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
  }
];

const loadData = ({ skip, limit, sortInfo, groupBy }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '') + (groupBy && groupBy.length ? '&groupBy=' + groupBy : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [stickyGroupRows, setStickyGroupRows] = useState(false);
  const [groupBy, setGroupBy] = useState([]);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <p><Button onClick={() => setGroupBy(['permissionToCall', 'lastName'])}>Group by permissionToCall and lastName</Button></p>
      <p><Button onClick={() => setGroupBy([])}>Remove grouping</Button></p>
      <p>In this example, you cannot group by id or email.</p>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={stickyGroupRows}
          onChange={setStickyGroupRows}
        >
          Use sticky group rows
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        stickyGroupRows={stickyGroupRows}
        groupBy={groupBy}
        onGroupByChange={setGroupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool|Object
default: undefined

Specifying a truthy value, will show a dedicated group column as the first column of the <ReactDataGrid />. When groupColumn=true, the checkbox column with the default configuration will be displayed. However, you can use an object as the value for this prop, so you can configure any column properties just like for a normal <ReactDataGrid /> column.
You can use groupColumn.renderGroupValue if you want to customize how the group value is rendered in the group column.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 400 }

const groupColumn = {
  renderGroupValue: ({ value }) => value === 'true'? 'Yes': value === 'false' ? 'No': value
}

const columns = [
  { name: 'id', type: 'number', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' },
  {
    name: 'permissionToCall', minWidth: 80,
    header: 'Permission to call',
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value === true || value === 'true' ? 'Calls allowed' : 'No calls allowed'
  }
]

const loadData = ({ sortInfo }) => {
  return fetch(DATASET_URL + '?skip=0&limit=20&sortInfo='+JSON.stringify(sortInfo))
    .then(response => response.json())
}

const App = () => {
  const [stickyGroupRows, setStickyGroupRows] = useState(false);
  const [showGroupColumn, setShowGroupColumn] = useState(false);
  const [groupBy, setGorupBy] = useState(['permissionToCall'])

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <h3>GroupBy example with default grouping</h3>

      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={stickyGroupRows}
          onChange={setStickyGroupRows}
        >
          Use sticky group rows
        </CheckBox>
      </div>

      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={showGroupColumn}
          onChange={setShowGroupColumn}
        >
          Use dedicated group column
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        groupColumn={showGroupColumn? groupColumn: null}
        stickyGroupRows={stickyGroupRows}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn({ value, data, groupSummary })
default: undefined

Can be used to customize the rendering of the groupColumn=true
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 400 }

const groupColumn = {
  renderGroupValue: ({ value }) => value === 'true'? 'Yes': value === 'false' ? 'No': value
}

const columns = [
  { name: 'id', type: 'number', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' },
  {
    name: 'permissionToCall', minWidth: 80,
    header: 'Permission to call',
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value === true || value === 'true' ? 'Calls allowed' : 'No calls allowed'
  }
]

const loadData = ({ sortInfo }) => {
  return fetch(DATASET_URL + '?skip=0&limit=20&sortInfo='+JSON.stringify(sortInfo))
    .then(response => response.json())
}

const App = () => {
  const [stickyGroupRows, setStickyGroupRows] = useState(false);
  const [showGroupColumn, setShowGroupColumn] = useState(false);
  const [groupBy, setGorupBy] = useState(['permissionToCall'])

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <h3>GroupBy example with default grouping</h3>

      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={stickyGroupRows}
          onChange={setStickyGroupRows}
        >
          Use sticky group rows
        </CheckBox>
      </div>

      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={showGroupColumn}
          onChange={setShowGroupColumn}
        >
          Use dedicated group column
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        groupColumn={showGroupColumn? groupColumn: null}
        stickyGroupRows={stickyGroupRows}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

Specifies a group for the columns generated for grouping.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

const groups = [{ name: 'permission', header: 'Permission' }]

const columns = [
  { name: 'id', type: 'number', defaultWidth: 50, header: 'Id', defaultVisible: false },
  {
    name: 'permissionToCall',
    header: 'Permission to call',
    defaultWidth: 200,
    group: 'permission',
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
  },
  { name: 'firstName', groupBy: false, defaultWidth: 150, header: 'First Name' },
  { name: 'lastName', defaultWidth: 150, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultWidth: 150, header: 'Email' }
]

const loadData = ({ skip, limit, sortInfo, groupBy }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '') + (groupBy && groupBy.length ? '&groupBy=' + groupBy : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [groupBy, setGroupBy] = useState(['permissionToCall'])

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <p>In this example, you cannot group by first name or email.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        groupBy={groupBy}
        groups={groups}
        hideGroupByColumns={false}
        groupForGroupColumns="permission"
        onGroupByChange={setGroupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Number
default: 30

Specifies the nesting width for grouping. This is the width of the columns automatically generated for grouping.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'
import ComboBox from '@inovua/reactdatagrid-community/packages/ComboBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', groupBy: false, type: 'number', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'firstName', defaultWidth: 150, header: 'First Name' },
  { name: 'lastName', defaultWidth: 150, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultWidth: 150, header: 'Email' },
  {
    name: 'permissionToCall', defaultWidth: 200,
    header: 'Permission to call',
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
  }
]

const loadData = ({ skip, limit, sortInfo, groupBy }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '') + (groupBy && groupBy.length ? '&groupBy=' + groupBy : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data=> {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const nestingSizeDataSource = [
  { id: 30, label: 'Size: 30px' },
  { id: 50, label: 'Size: 50px' },
  { id: 70, label: 'Size: 70px' },
  { id: 100, label: 'Size: 100px' },
  { id: 150, label: 'Size: 150px' },
]

const App = () => {
  const [groupBy, setGroupBy] = useState(['permissionToCall'])
  const [groupNestingSize, setGroupNestingSize] = useState(50)

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        Group nesting size:{' '}
        <ComboBox
          style={{ width: 150}}
          inlineFlex
          collapseOnSelect
          clearIcon={false}
          searchable={false}
          changeValueOnNavigation
          dataSource={nestingSizeDataSource}
          value={groupNestingSize}
          onChange={setGroupNestingSize}
        />
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        groupNestingSize={groupNestingSize}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

default: undefined

The character to be used as group separator, when specifying the collapsed groups in a <ReactDataGrid />.
The keys of the selected object should be the "paths" to collapsed groups. For example, if records are first grouped by country, and "uk" is a country shared by many records, and then grouped by city, with "London" being the city value for many items, then "uk/London" (a concatenation of the two, separated by groupPathSeparator) is the key to be used in the collapsed object in order to render "London" people as collapsed.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultWidth: 140, header: 'Country' },
  { name: 'city', defaultWidth: 140, header: 'City' },
  { name: 'email', defaultWidth: 140, defaultFlex: 1, header: 'Email' }
]

const App = () => {
  const [groupBy, setGroupBy] = useState(['country','city'])
  const [collapsedGroups, setCollapsedGroups] = useState({ 'uk#London': true, 'uk#Bristol': true })
  const [expandedGroups, setExpandedGroups] = useState(true)

  const onGroupCollapseChange = useCallback((collapsedGroups, expandedGroups) => {
    setCollapsedGroups(collapsedGroups)
    setExpandedGroups(expandedGroups)
  }, [])

  return (
    <div>
      <p>
        Collapsed groups: {JSON.stringify(Object.keys(collapsedGroups))}.
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        collapsedGroups={collapsedGroups}
        expandedGroups={expandedGroups}
        groupPathSeparator="#"
        onGroupCollapseChange={setCollapsedGroups}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Array
default: undefined

Specifies a group property to <ReactDataGrid />.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80, hedaer: 'Id', defaultVisible: false },
  { name: 'firstName', group: 'personalInfo', defaultFlex: 1, header: 'First Name' },
  { name: 'age', group: 'personalInfo', type: 'number', header: 'Age' },
  { name: 'email', group: 'contactInfo', defaultFlex: 1, header: 'Email' },
  { name: 'phone', group: 'contactInfo', header: 'Phone'  },
  { name: 'city', group: 'location', header: 'City' },
  { name: 'streetName', group: 'street', defaultFlex: 1, header: 'Street name' },
  { name: 'streetNo', group: 'street', type: 'number', header: 'Street no' }
]
const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', header: 'Personal info' },
  { name: 'contactInfo', header: 'Contact info' },
  { name: 'location', header: 'Location' }
]

const dataSource = [
  { id: 0, firstName: 'Bob', age: 25, email: 'bobby@whocares.com', phone: '+7403 456 768', city: 'Paris', streetName: 'Champs Elysee', streetNo: 34 },
  { id: 1, firstName: 'Lynda', age: 38, email: 'lynda@idont.com', phone: '+7103 66 98 768', city: 'London', streetName: 'St Mary', streetNo: 14 },
  { id: 2, firstName: 'Richard', age: 18, email: 'richy@rich.com', phone: '+173 668 08 83', city: 'Manchester', streetName: 'St Robert', streetNo: 53 },
  { id: 3, firstName: 'Michael', age: 45, email: 'mike@mikey.com', phone: '+075 0628 156 74', city: 'Los Angeles', streetName: 'Greenfield', streetNo: 24 },
  { id: 4, firstName: 'Martin', age: 12, email: 'martin@bobson.com', phone: '+173 5624 675 462', city: 'San Jose', streetName: 'Patrick Ball', streetNo: 67 }
]
const gridStyle = { minHeight: 500 }

export default () => <div>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>

Bool
default: undefined

Specify false to make a column group non-draggable. By default column groups are draggable.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', type: 'number', minWidth: 50, header: 'Id', defaultVisible: false },
  { name: 'firstName', group: 'personalInfo', defaultFlex: 1, header: 'First Name' },
  { name: 'age', group: 'personalInfo', type: 'number', minWidth: 50, header: 'Age' },
  { name: 'email', group: 'contactInfo', defaultFlex: 1, header: 'Email' },
  { name: 'phone', group: 'contactInfo', defaultFlex: 1, header: 'Phone' },
  { name: 'city', group: 'location', defaultFlex: 1, header: 'City' },
  { name: 'streetName', group: 'street', defaultFlex: 1, header: 'Street name' },
  { name: 'streetNo', group: 'street', type: 'number', minWidth: 50, header: 'Street no' }
]

const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', group: 'details', header: 'Personal info' },
  { name: 'contactInfo', group: 'details', header: 'Contact info' },
  { name: 'location', group: 'details', draggable: false, header: 'Location' }
]

const dataSource = [
  { id: 0, firstName: 'Bob', age: 25, email: 'bobby@whocares.com', phone: '+7403 456 768', city: 'Paris', streetName: 'Champs Elysee', streetNo: 34 },
  { id: 1, firstName: 'Lynda', age: 38, email: 'lynda@idont.com', phone: '+7103 66 98 768', city: 'London', streetName: 'St Mary', streetNo: 14 },
  { id: 2, firstName: 'Richard', age: 18, email: 'richy@rich.com', phone: '+173 668 08 83', city: 'Manchester', streetName: 'St Robert', streetNo: 53 },
  { id: 3, firstName: 'Michael', age: 45, email: 'mike@mikey.com', phone: '+075 0628 156 74', city: 'Los Angeles', streetName: 'Greenfield', streetNo: 24 },
  { id: 4, firstName: 'Martin', age: 12, email: 'martin@bobson.com', phone: '+173 5624 675 462', city: 'San Jose', streetName: 'Patrick Ball', streetNo: 67 }
]
const gridStyle = { minHeight: 500 }

export default () => <div>
  <p>Location group is not draggable in this example</p>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>

Array
default: undefined

Nesting a group inside another group can be done by specifying a groups.group property - eg: say you want to nest a 'street' group inside a 'location' group - you have to specify { name: 'street', group: 'location'} which means the 'street' group is nested inside the 'location' group.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 40, header: 'Id', defaultVisible: false },
  { name: 'firstName', group: 'personalInfo', defaultFlex: 2, header: 'First Name' },
  { name: 'age', group: 'personalInfo', type: 'number', defaultWidth: 50, header: 'Age' },
  { name: 'email', group: 'contactInfo', defaultFlex: 2, header: 'Email' },
  { name: 'phone', group: 'contactInfo', defaultFlex: 1, header: 'Phone' },
  { name: 'city', group: 'location', defaultFlex: 1, header: 'City' },
  { name: 'streetName', group: 'street', defaultFlex: 1, header: 'Street name' },
  { name: 'streetNo', group: 'street', type: 'number', defaultWidth: 50, header: 'Street no' }
]
const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', header: 'Personal info' },
  { name: 'contactInfo', header: 'Contact info' },
  { name: 'location', header: 'Location' }
]

const dataSource = [
  { id: 0, firstName: 'Bob', age: 25, email: 'bobby@whocares.com', phone: '+7403 456 768', city: 'Paris', streetName: 'Champs Elysee', streetNo: 34 },
  { id: 1, firstName: 'Lynda', age: 38, email: 'lynda@idont.com', phone: '+7103 66 98 768', city: 'London', streetName: 'St Mary', streetNo: 14 },
  { id: 2, firstName: 'Richard', age: 18, email: 'richy@rich.com', phone: '+173 668 08 83', city: 'Manchester', streetName: 'St Robert', streetNo: 53 },
  { id: 3, firstName: 'Michael', age: 45, email: 'mike@mikey.com', phone: '+075 0628 156 74', city: 'Los Angeles', streetName: 'Greenfield', streetNo: 24 },
  { id: 4, firstName: 'Martin', age: 12, email: 'martin@bobson.com', phone: '+173 5624 675 462', city: 'San Jose', streetName: 'Patrick Ball', streetNo: 67 }
]
const gridStyle = { minHeight: 500 }

export default () => <div>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>

String|React.Node
default: undefined

Specifies a header for a group.
For any specified group, you can use the groups.header property to customize the content inside the group header. Think of group headers just like column headers.
When columns that are in the same group are siblings, their group header is extended to cover all related siblings. When the user changes the column order, the <ReactDataGrid /> is smart enough to know how to split group headers and where new groups begin.
So all you need to pass to the <ReactDataGrid /> is the array of columns you want to display and it will figure out the correct nesting/stacking of column group headers.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', type: 'number', minWidth: 50, header: 'Id', defaultVisible: false },
  { name: 'firstName', group: 'personalInfo', defaultFlex: 2, header: 'First Name' },
  { name: 'age', group: 'personalInfo', type: 'number', minWidth: 50, header: 'Age' },
  { name: 'email', group: 'contactInfo', defaultFlex: 2, header: 'Email' },
  { name: 'phone', group: 'contactInfo', defaultFlex: 1, header: 'Phone' },
  { name: 'city', group: 'location', defaultFlex: 1, header: 'City' },
  { name: 'streetName', group: 'street', defaultFlex: 1, header: 'Street name' },
  { name: 'streetNo', group: 'street', type: 'number', minWidth: 50, header: 'Street no' }
]

const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', header: 'Information about you' },
  { name: 'contactInfo', header: <span style={{ color: '#7986cb' }}>Contact</span> },
  { name: 'location', header: <span style={{ color: '#ef9a9a' }}>Where you live</span> }
]

const dataSource = [
  { id: 0, firstName: 'Bob', age: 25, email: 'bobby@whocares.com', phone: '+7403 456 768', city: 'Paris', streetName: 'Champs Elysee', streetNo: 34 },
  { id: 1, firstName: 'Lynda', age: 38, email: 'lynda@idont.com', phone: '+7103 66 98 768', city: 'London', streetName: 'St Mary', streetNo: 14 },
  { id: 2, firstName: 'Richard', age: 18, email: 'richy@rich.com', phone: '+173 668 08 83', city: 'Manchester', streetName: 'St Robert', streetNo: 53 },
  { id: 3, firstName: 'Michael', age: 45, email: 'mike@mikey.com', phone: '+075 0628 156 74', city: 'Los Angeles', streetName: 'Greenfield', streetNo: 24 },
  { id: 4, firstName: 'Martin', age: 12, email: 'martin@bobson.com', phone: '+173 5624 675 462', city: 'San Jose', streetName: 'Patrick Ball', streetNo: 67 }
]
const gridStyle = { minHeight: 500 }

export default () => <div>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>

{ initialValue: any, reducer: (acc, current) => any, complete: (value, arr) => any}
default: undefined

Specifies how to compute a summary for the grid when there is grouping.
The groupSummaryReducer object has the following shape:
  • initialValue - the initial value to be used for the summary computation - generally a number/string/etc
  • reducer(accumulator, data) - the reducer function - basically computes the summary from the accumulated value (at first call, this will equal the initialValue) and the data object for the item at which we are doing the computation
  • complete(accumulatedValue, array) - can be used for doing one last computation at the end of the iteration - for example useful for computing the average of a value. The first argument is the accumulated value, while the second is the array on which the summary was computed against
To use column specific grouping, see columns.groupSummaryReducer.
In custom render functions defined for columns, when the group row is being rendered, you have access to the group summaries via the data.groupColumnSummary object, which has a key for each of the columns that define a column.groupSummaryReducer.
Also data.groupSummary is available in the render function in case you have definedgroupSummaryReducer at grid-level.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 600, marginTop: 10 }

let cities;

const sum = (a,b) => a + b

const columns = [
  {
    name: 'name',
    defaultFlex: 1,
    header: 'City',
    render: ({ value, data }) => {

      if (data.__group){
        return <React.Fragment>
          <b>Avg city population: {Math.round(data.groupSummary)}</b>
        </React.Fragment>
      }

      return value
    },
  },
  { name: 'country', defaultFlex: 1, header: 'Country'},
  {
    name: 'population',
    type: 'number',
    defaultFlex: 1,
    header: 'Population',

    render: ({ value, data }) => {

      // if you want to custom-render the summary value for this column
      // you can do so

      return data.__group ? (
        <React.Fragment>
          <b>Total: </b>
          {value}{' '}
        </React.Fragment>
      ) : (
        value
      );
    },

    groupSummaryReducer: {
      initialValue: 0,
      reducer: sum
    }
  }
];

const App = () => {
  return (
    <div>
      <h3>groupSummaryReducer demo at grid-level</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        groupColumn={{
          defaultWidth: 250,
          renderGroupValue: ({ value, data }) => {
            return <React.Fragment>
              {value} - avg city population: {Math.round(data.groupSummary)}
            </React.Fragment>
          }
        }}
        groupSummaryReducer={{
          initialValue: 0,
          reducer: (acc, data) => acc + data.population,
          complete: (value, arr) => value/arr.length
        }}
        columns={columns}
        dataSource={cities}
        defaultGroupBy={['country']}
      />
    </div>
  );
}

cities = [
  {
    id: 'ny',
    country: 'USA',
    name: 'New York City',
    population: 1000
  },
  {
    id: 'la',
    country: 'USA',
    name: 'Los Angeles',
    population: 150
  },
  {
    id: 'paris',
    country: 'France',
    name: 'Paris',
    population: 2000
  },
  {
    id: 'london',
    name: 'London',
    country: 'UK',
    population: 3000
  },
  {
    id: 'SF',
    name: 'San Francisco',
    country: 'USA',
    population: 3900
  },
  {
    id: 'ly',
    name: 'Lyon',
    country: 'France',
    population: 980
  },
  {
    id: 'ma',
    name: 'Manchester',
    country: 'UK',
    population: 2000
  }
]

export default () => <App />

(computedPropsRef: MutableRef) => void
default: undefined

A function used to get a reference to the grid (more exactly, a ref to the grid computed props).
The first argument passed to this function is a React ref object.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import Button from '@inovua/reactdatagrid-community/packages/Button'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb'
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb'
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const defaultExpandedNodes = { 1: true, 2: true, '3/1': true }

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [dataSource, setDataSource] = useState(treeData)
  const [expandedNodes, setExpandedNodes]= useState(defaultExpandedNodes)
  const [clearNodeCacheOnDataSourceChange, setClearNodeCacheOnDataSourceChange] = useState(true)

  const onExpandedNodesChange = useCallback(({ expandedNodes }) => {
    setExpandedNodes(expandedNodes)
  }, [])

  return (
    <div>
      <p>
        <CheckBox
          checked={clearNodeCacheOnDataSourceChange}
          onChange={setClearNodeCacheOnDataSourceChange}
        >Clear node cache on data source change</CheckBox>
      </p>
      <p>
        <Button
          onClick={() => {
            gridRef.current.setItemPropertyAt(0, 'name', 'Apps')
          }}
        >
          Set "name" property for first node to "Apps"
        </Button>
      </p>
      <p>
        <Button
          onClick={() => setDataSource([].concat(treeData))}>
            Update dataSource
          </Button>
        <p>If "Clear node cache" is true, and the first node is changed, it should revert to the initial value when updating the dataSource
        </p>
      </p>
      <ReactDataGrid
        handle={setGridRef}
        treeColumn="name"
        clearNodeCacheOnDataSourceChange={clearNodeCacheOnDataSourceChange}
        expandedNodes={expandedNodes}
        onExpandedNodesChange={onExpandedNodesChange}
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

If specified, this object will be passed to the <ReactDataGrid /> header (this is the wrapper component containing the headers for all grid columns) and be used as DOM props. Can contain properties like className, style, etc.
For DOM props passed directly to a specific column header, see columns.headerDOMProps.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }
const headerProps = {
  style: {
    height: 120,
    background: 'tomato',
    color: 'white'
  }
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country' },
  { name: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age ' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        headerProps={headerProps}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Specifies whether the columns used for grouping should be hidden or not.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'country', defaultFlex: 1, header: 'Country' },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  const [hideGroupByColumns, sethHideGroupByColumns] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={hideGroupByColumns}
          onChange={sethHideGroupByColumns}
        >
          Hide group by columns
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={['country']}
        hideGroupByColumns={hideGroupByColumns}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

This is an object you can use to translate/internationalize labels/text content used in the <ReactDataGrid />.
Beware of specifying an object with just a few of those keys - the other keys will be undefined, so they won't be displayed. Instead, also copy the default keys/values from DataGrid.defaultProps.i18n!
The following keys are available (with their default values):
  • pageText='Page '
  • ofText=' of '
  • perPageText='Results per page'
  • showingText='Showing '
  • clearAll='Clear all'
  • clear='Clear'
  • showFilteringRow='Show filtering row'
  • hideFilteringRow='Hide filtering row'
  • dragHeaderToGroup='Drag header to group'
  • disable='Disable'
  • enable='Enable'
  • disable='Disable'
  • sortAsc='Sort ascending'
  • sortDesc='Sort descending'
  • unsort='Unsort'
  • group='Group'
  • ungroup='Ungroup'
  • lockStart='Lock start'
  • lockEnd='Lock end'
  • unlock='Unlock'
  • columns='Columns'
  • contains='Contains'
  • startsWith='Starts with'
  • endsWith='Ends with'
  • notContains='Does not contain'
  • neq='Does not equal'
  • eq='Equals'
  • notEmpty='Not empty'
  • empty='Empty'
  • lt='Less than'
  • lte='Less than or equal'
  • gt='Greater than'
  • gte='Greater than or equal'
  • calendar.todayButtonText='Today'
  • calendar.clearButtonText='Clear'
  • calendar.okButtonText='OK'
  • calendar.cancelButtonText='Cancel'
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1 }
]

const dataSource = [
  { name: 'John Lewis', age: 35, id: 'john4' },
  { name: 'Mary Stones', age: 25, id: 'mary8' },
  { name: 'Mary Stones', age: 43, id: 'mary67' },
  { name: 'Andrew Clark', age: 31, id: 'and99' },
  { name: 'Vanessa Williams', age: 29, id: 'vane2' },
  { name: 'Terence More', age: 27, id: 'tere0' },
  { name: 'Leonard Stevenson', age: 48, id: 'leo64' }
]

const gridStyle = {
  minHeight: 450
}

const i18n = Object.assign({}, ReactDataGrid.defaultProps.i18n, {
  sortAsc: 'Execute ASC sort',
  sortDesc: 'Execute DESC sort',
  clear: 'Remove',
  clearAll: 'Remove All'
})

export default () => <ReactDataGrid
  i18n={i18n}
  columns={columns}
  dataSource={dataSource}
  style={gridStyle}
/>

String
default: "id"

The simplest dataSource is an array of objects, with properties matching the names of the <ReactDataGrid /> columns. DataSource objects can contain any other properties, and will generally contain an identifier property - most of the times named id that gives uniqueness to <ReactDataGrid /> rows. This identifier property name should be used as the idProperty to help uniquely identify <ReactDataGrid /> rows.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'uniqueId', header: 'Id', defaultWidth: 80 },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1 }
]

const dataSource = [
  { name: 'John Lewis', age: 35, uniqueId: 'john4' },
  { name: 'Mary Stones', age: 25, uniqueId: 'mary8' },
  { name: 'Mary Stones', age: 43, uniqueId: 'mary67' },
  { name: 'Andrew Clark', age: 31, uniqueId: 'and99' },
  { name: 'Vanessa Williams', age: 29, uniqueId: 'vane2' },
  { name: 'Terence More', age: 27, uniqueId: 'tere0' },
  { name: 'Leonard Stevenson', age: 48, uniqueId: 'leo64' }
]

const gridStyle = {
  minHeight: 250
}

export default () => <div>
  <ReactDataGrid
    idProperty="uniqueId"
    columns={columns}
    dataSource={dataSource}
    style={gridStyle}
  />
</div>

Fn(info)
default: undefined

By default, rows/nodes/groups are collapsed when Alt+ArrowLeft is pressed. The default implementation of this function is ({event}) => event.key === 'ArrowLeft' && event.altKey;
By providing a different implementation, you can change the key combination on which rows/nodes/groups are collapsed.
See related isExpandKeyPressed
The info param has an event property and also many properties with information about the currently active row:
  • event - the event object
  • data - the current active row. An alias of activeItem
  • index - the current active index. An alias of activeIndex
  • activeItem - the current active row
  • activeIndex - the current active index
  • grid - a reference to the <ReactDataGrid /> instance
  • isGroup - boolean - whether the current row is a group row
  • selectionEnabled - boolean - whether row selection is enabled
  • treeEnabled - boolean - whether tree functionality is enabled
  • rowExpandEnabled - boolean - whether row expand is enabled
  • nodeExpanded - boolean - whether the node is expanded
  • nodeExpandable - boolean - whether the node is expandable
  • rowExpandable - boolean - whether the row is expandable
  • rowExpanded - boolean - whether the row is expanded
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const isExpandKeyPressed = ({ event }) => event.key === 'ArrowRight' && event.shiftKey
const isCollapseKeyPressed = ({ event }) => event.key === 'ArrowLeft' && event.shiftKey

const renderRowDetails = ({ data }) => {
  return <div style={{ padding: 20}}>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const defaultExpandedRows = { 1: true, 2: true }

const App = () => {
  return (
    <div>
      <p>
        Use Shift + Arrow keys to expand/collapse rows.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        isExpandKeyPressed={isExpandKeyPressed}
        isCollapseKeyPressed={isCollapseKeyPressed}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(info)
default: undefined

By default, rows/nodes/groups are expanded when Alt+ArrowRight is pressed. The default implementation of this function is ({event}) => event.key === 'ArrowRight' && event.altKey;
By providing a different implementation, you can change the key combination on which rows/nodes/groups are expanded.
The info param has an event property and also many properties with information about the currently active row:
  • event - the event object
  • data - the current active row. An alias of activeItem
  • index - the current active index. An alias of activeIndex
  • activeItem - the current active row
  • activeIndex - the current active index
  • grid - a reference to the <ReactDataGrid /> instance
  • isGroup - boolean - whether the current row is a group row
  • selectionEnabled - boolean - whether row selection is enabled
  • treeEnabled - boolean - whether tree functionality is enabled
  • rowExpandEnabled - boolean - whether row expand is enabled
  • nodeExpanded - boolean - whether the node is expanded
  • nodeExpandable - boolean - whether the node is expandable
  • rowExpandable - boolean - whether the row is expandable
  • rowExpanded - boolean - whether the row is expanded
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const isExpandKeyPressed = ({ event }) => event.key === 'ArrowRight' && event.shiftKey
const isCollapseKeyPressed = ({ event }) => event.key === 'ArrowLeft' && event.shiftKey

const renderRowDetails = ({ data }) => {
  return <div style={{ padding: 20}}>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const defaultExpandedRows = { 1: true, 2: true }

const App = () => {
  return (
    <div>
      <p>
        Use Shift + Arrow keys to expand/collapse rows.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        isExpandKeyPressed={isExpandKeyPressed}
        isCollapseKeyPressed={isCollapseKeyPressed}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ node, nodeProps })
default: undefined

Can be used to have the last word in deciding whether a node is async or not.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb',
        nodes: null
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb',
        nodes: null
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const defaultExpandedNodes = { 3: true, '3/1': true }

const loadNode = ({ node, nodeProps }) => {
  return new Promise((resolve, reject) => {

    setTimeout(() => {
      if (Array.isArray(node.nodes)) {
        return resolve(node.nodes)
      }
      if (nodeProps.depth >=4 ) {
        resolve([
          { id: 1, name: 'First child of ' + node.name },
          { id: 2, name: 'Second child of ' + node.name }
        ])
      }
      resolve([
        { id: 1, name: 'First child of ' + node.name, nodes: null },
        { id: 2, name: 'Second child of ' + node.name, nodes: null }
      ])
    }, 200)
  })
}

const isNodeAsync = ({ node }) => {
  if (node.name === 'Applications') {
    return true
  }

  return node.nodes === null
}

const App = () => {
  return (
    <div>
      <p>DataGrid with the "Applications" node forced to async</p>
      <ReactDataGrid
        isNodeAsync={isNodeAsync}
        loadNode={loadNode}
        defaultExpandedNodes={defaultExpandedNodes}
        treeColumn={'name'}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Fn({ node, nodeProps })
default: undefined

Can be used to have the last word in deciding whether a node is a leaf node or not.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb',
        nodes: null
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb',
        nodes: null
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const defaultExpandedNodes = { 3: true, '3/1': true }

const loadNode = ({ node, nodeProps }) => {
  return new Promise((resolve, reject) => {

    setTimeout(() => {
      if (nodeProps.depth >=4 ) {
        resolve([
          { id: 1, name: 'First child of ' + node.name },
          { id: 2, name: 'Second child of ' + node.name }
        ])
      }
      resolve([
        { id: 1, name: 'First child of ' + node.name, nodes: null },
        { id: 2, name: 'Second child of ' + node.name, nodes: null }
      ])
    }, 200)
  })
}

const isNodeLeaf = ({ node }) => {
  if (node.name === 'Applications') {
    return true
  }

  return node.nodes === null
}

const App = () => {
  return (
    <div>
      <p>DataGrid with the "Applications" node forced to be a leaf</p>
      <ReactDataGrid
        isNodeLeaf={isNodeLeaf}
        loadNode={loadNode}
        defaultExpandedNodes={defaultExpandedNodes}
        treeColumn={'name'}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Fn({ id, data, rowIndex })
default: undefined

Can be used to make some rows unexpandable.
The argument passed to this function is an object which is reused, so make sure you don't store a reference to the object containing the id, data or rowIndex properties, but rather store the property values.
For a more performant alternative, use unexpandableRows.
When unexpandableRows prop is specified, this prop is no longer called.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const renderRowDetails = ({ data }) => {
  return <div style={{ padding: 20}}>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const App = () => {
  const isRowExpandable = useCallback(({ data }) => {
    return data.age >= 30
  }, [])

  return (
    <ReactDataGrid
      idProperty="id"
      isRowExpandable={isRowExpandable}
      style={gridStyle}
      rowExpandHeight={400}
      renderRowDetails={renderRowDetails}
      columns={columns}
      dataSource={people}
    />
  );
}

export default () => <App />

Fn({ event })
default: undefined

The default keyboard shortcut to start edit on the active row is Ctrl+E.
Can be used to customise the keyboard shortcut used to trigger editing on the active row.
The default implementation is just ({ event }) => event.key === 'e' && event.ctrlKey
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const isStartEditKeyPressed = ({ event }) => event.key === 'g' && event.ctrlKey

const columns = [
  { name: 'id', minWidth: 70, type: 'number', header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, minWidth: 200, header: 'Name' },
  { name: 'country', defaultFlex: 1, minWidth: 100, render: ({ value })=> flags[value] ? flags[value] : value, header: 'Country' },
  { name: 'city', defaultFlex: 1, minWidth: 200, header: 'City' },
  { name: 'age', minWidth: 150, type: 'number', header: 'Age' }
]

const App = () => {
  const [dataSource, setDataSource] = useState(people)

  const onEditComplete = useCallback(({ value, columnId, rowIndex }) => {
    const data = [...dataSource];
    data[rowIndex][columnId] = value;

    setDataSource(data)
  }, [dataSource])

  return (
    <div>
      <h3>Trigger inline edit via a custom keyboard shortcut: Ctrl+G</h3>
      <ReactDataGrid
        isStartEditKeyPressed={isStartEditKeyPressed}
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable={true}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Number
default: 10

When the user navigates the <ReactDataGrid /> with keyboard navigation and hits PageUp or PageDown, the activeIndex is incremented (on PageDown) or decremented (on PageUp) by the amount specified via the keyPageStep.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'country', defaultWidth: 150, header: 'Country' },
  { name: 'age', defaultWidth: 150, type: 'number', header: 'Age' },
  {
    id: 'desc',
    header: 'Description',
    defaultWidth: 250,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  return (
    <div>
      <h3>Grid with keyPageStep=4</h3>
      <p>Focus the grid and press PageDown/PageUp to navigate by 4 rows downwards/upwards!</p>
      <ReactDataGrid
        idProperty="id"
        keyPageStep={4}
        defaultActiveIndex={6}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

string
default: undefined

Contains the license key for the enterprise version of the <ReactDataGrid />.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'First Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  return (
    <ReactDataGrid
      idProperty="id"
      style={gridStyle}
      columns={columns}
      dataSource={people}
      licenseKey="" /* USE LICENSE KEY HERE */
    />
  );
}

export default () => <App />

Number
default: 50

The page size for the <ReactDataGrid />, when pagination is enabled.
This is an controlled prop. For the uncontrolled version, see defaultLimit.
When using this controlled prop, make sure you update its value when onLimitChange is triggered, so the dataSource (most often, a function when the <ReactDataGrid /> has remote pagination) can be reloaded with the correct limit value.
The pagination toolbar has a ComboBox displaying a choice of page-sizes. The options in the ComboBox can be configured via pageSizes.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 500, marginTop: 10 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const loadData = ({ skip, limit, sortInfo }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [limit, setLimit] = useState(10);
  const [loading, setLoading] = useState(false);

  const dataSource = useCallback(loadData, [])

  const updateLimit = useCallback((amount) => {
    let newLimit = limit + amount;
    newLimit = Math.min(newLimit, 100);
    newLimit = Math.max(newLimit, 0);

    setLimit(newLimit);
  }, [limit])

  const disabled = loading || Array.isArray(dataSource)

  return (
    <div>
      <p>Try to update the page size in the combo to see the limit change</p>
      <p>Current limit (page size): {limit}.</p>
      <div style={{ marginBottom: 20 }}>
        <Button style={{ marginRight: 8 }} onClick={() => updateLimit(10)} disabled={disabled}>limit += 10</Button>
        <Button onClick={() => updateLimit(-10)} disabled={disabled || limit === 0}>limit -= 10</Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination
        limit={limit}
        onLimitChange={setLimit}
        loading={loading}
        onLoadingChange={setLoading}
        dataSource={dataSource}
      />
    </div>
  );
}
export default () => <App />

Bool
default: undefined

Specifies that the <ReactDataGrid /> should use live pagination
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 500, marginTop: 10 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const loadData = ({ skip, limit }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data => {
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const [livePagination, setLivePagination] = useState(true);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={livePagination} onChange={setLivePagination} >
          Live pagination
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        key={'grid-' + livePagination}
        style={gridStyle}
        columns={columns}
        livePagination={livePagination}
        pagination
        sortable={false}
        dataSource={dataSource}
        limit={15}
      />
    </div>
  );
}

export default () => <App />

Number
default: 50

When livePagination is used, and subsequent pages need to be loaded, the load mask is hidden with this configured delay in order to avoid flashing.

Bool
default: undefined

Specifies whether the load mask should be visible or not.
This is a controlled prop. For the uncontrolled alternative, use defaultLoading.
When pagination or remote dataSource is used, the uncontrolled defaultLoading is used by the <ReactDataGrid />. If you are using the controlled loading, you need to make sure the loading mask is displayed while fetching remote data.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultWidth: 150, type: 'number' }
]

const App = () => {
  const [loading, setLoading] = useState(false)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={loading} onChange={setLoading}>
          Show load mask
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        loading={loading}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

React.Node
default: undefined

When the load mask is displayed (see loading), you can optionally show a custom message, as specified by this prop.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const pleaseWait = <b>Please wait while loading ... </b>

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 60 },
  { name: 'name', header: 'Name', defaultFlex: 1, defaultWidth: 100 },
  { name: 'country', header: 'Country', defaultFlex: 1, defaultWidth: 100 },
  { name: 'city', header: 'City', defaultFlex: 1, defaultWidth: 100 },
  { name: 'age', header: 'Age', defaultWidth: 150, type: 'number' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        loading={true}
        loadingText={pleaseWait}
        columns={columns}
        dataSource={[]}
      />
    </div>
  );
}

export default () => <App />

Fn({ node, nodeProps })
default: undefined

For an async node (a node that has nodes===null), will be called when the node is expanded (on every expand). Should either return an array or a Promise resolving to an array.
For the same functionality, but only called once (it caches the results), see loadNodeOnce.
This function can also be called when using the loadNodeAsync property available on the columns.render function.
node is a reference to the data item being expanded.
nodeProps is an object with the following properties:
  • expanded: Boolean
  • loading: Boolean
  • depth: Number - the depth from the topmost node to the current node. Top-level nodes have a depth of 0
  • path: String - the path from the topmost node to the current node
  • parentNodeId: String/Number - the id of the parent node
  • leafNode: Boolean
  • asyncNode: Boolean
  • childIndex: Number - the index of the current node among its sibling nodes
By default, when an async node is collapsed, and loadNode is used, all it's children at any level of nesting are also collapsed (in order to have fresh data on the next expand) - to modify this behaviour, see collapseChildrenOnAsyncNodeCollapse.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb',
        nodes: null
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb',
        nodes: null
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const loadNode = ({ node, nodeProps }) => {
  return new Promise((resolve, reject) => {

    setTimeout(() => {
      if (nodeProps.depth >=4 ) {
        resolve([
          { id: 1, name: 'First child of ' + node.name },
          { id: 2, name: 'Second child of ' + node.name }
        ])
      }
      resolve([
        { id: 1, name: 'First child of ' + node.name, nodes: null },
        { id: 2, name: 'Second child of ' + node.name, nodes: null }
      ])
    }, 200)
  })
}

const defaultExpandedNodes = { 1: true }

const App = () => {
  return (
    <div>
      <h3>TreeGrid with async nodes</h3>
      <ReactDataGrid
        treeColumn="name"
        loadNode={loadNode}
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Fn({ node, nodeProps })
default: undefined

For an async node (a node that has nodes===null), will be called when the node is first expanded (on subsequent expand actions, the same nodes returned initially by this method will be used). Should either return an array or a Promise resolving to an array.
For the same functionality, but called on every expand (so no cache), see loadNode.
This function can also be called when using the loadNodeAsync property available on the columns.render function.
node is a reference to the data item being expanded.
nodeProps is an object with the following properties:
  • expanded: Boolean
  • loading: Boolean
  • depth: Number - the depth from the topmost node to the current node. Top-level nodes have a depth of 0
  • path: String - the path from the topmost node to the current node
  • parentNodeId: String/Number - the id of the parent node
  • leafNode: Boolean
  • asyncNode: Boolean
  • childIndex: Number - the index of the current node among its sibling nodes
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb',
        nodes: null
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb',
        nodes: null
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const loadNodeOnce = ({ node, nodeProps }) => {
  return new Promise((resolve, reject) => {

    setTimeout(() => {
      if (nodeProps.depth >=4 ) {
        resolve([
          { id: 1, name: 'First child of ' + node.name },
          { id: 2, name: 'Second child of ' + node.name }
        ])
      }
      resolve([
        { id: 1, name: 'First child of ' + node.name, nodes: null },
        { id: 2, name: 'Second child of ' + node.name, nodes: null }
      ])
    }, 200)
  })
}

const defaultExpandedNodes = { 1: true }

const App = () => {
  return (
    <div>
      <h3>TreeGrid with async nodes</h3>
      <ReactDataGrid
        treeColumn="name"
        loadNodeOnce={loadNodeOnce}
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

If you want to make all columns unlockable, set this to false. For the most part, this prop is an alias to showColumnMenuLockOptions.
See showColumnMenuLockOptions for details.
Overriden by columns.lockable

default: undefined

Specifies locked rows to be used for the <ReactDataGrid /> - see locked rows page for more examples.
It's possible to have rows both at the start and at the end of the grid viewport.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import contactsDataSource from './data'

const gridStyle = { minHeight: 550, marginTop: 10 }

const columns = [
  { name: 'id', header: 'ID', defaultVisible: false, type: 'number', defaultWidth: 100 },
  { name: 'firstName', header: 'First Name', defaultWidth: 200 },
  { name: 'lastName', header: 'Last Name', defaultWidth: 200 },
  { name: 'email', header: 'Email', defaultFlex: 1 }
];

const App = () => {
  const [first, setFirst] = useState();
  const [second, setSecond] = useState();
  const [last, setLast] = useState();
  const [firstLocked, setFirstLocked] = useState(false);
  const [secondLocked, setSecondLocked] = useState(false);
  const [lastLocked, setLastLocked] = useState(false);
  const [showZebraRows, setShowZebraRows] = useState(false);
  const [useRowHeightForLockedRows, setUseRowHeightForLockedRows] = useState(true);
  const [dataSource, setDataSource] = useState(contactsDataSource);

  const update = useCallback((newState, fn) => {
    let data = [].concat(contactsDataSource)

    // we don't want to show locked rows in the dataSource

    if (newState.lastLocked) {
      // delete last 3
      setLast(data.splice(-3,3))
    }

    if (newState.secondLocked) {
      setSecond(data.splice(1, 1)[0])
    }

    if (newState.firstLocked) {
      setFirst(data.splice(0, 1)[0])
    }

    const newStateValue = Object.values(newState)[0];

    fn(newStateValue);
  }, [firstLocked, secondLocked, lastLocked])

  const lockedRows = []

  if (firstLocked) {
    lockedRows.push({
      position: 'start',
      render: ({column}, computedProps) => {
        return first ? first[column.name] : null
      }
    })
  }
  if (secondLocked) {
    lockedRows.push({
      position: 'start',
      render: ({column}, computedProps) => {
        return second ? second[column.name] : null
      }
    })
  }

  if (lastLocked) {
    lockedRows.push({
      position: 'end',
      render: ({column}, computedProps) => {
        const item = last? last[0] : null

        return item ? item[column.name] : null
      }
    })

    lockedRows.push({
      position: 'end',
      render: ({column}, computedProps) => {
        const item = last? last[1] : null

        return item ? item[column.name] : null
      }
    })

    lockedRows.push({
      position: 'end',
      render: ({column}, computedProps) => {
        const item = last? last[2] : null

        return item ? item[column.name] : null
      }
    })
  }

  return (
    <div>
      <h3>Locked rows demo</h3>

      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={firstLocked}
          onChange={firstLocked => update({ firstLocked }, setFirstLocked)}
        >
          Lock row 1
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={secondLocked}
          onChange={secondLocked => update({secondLocked}, setSecondLocked)}
        >
          Lock row 2
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={lastLocked}
          onChange={lastLocked => update({lastLocked}, setLastLocked)}
        >
          Lock last 3 rows at the bottom
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={showZebraRows}
          onChange={setShowZebraRows}
        >
          Show zebra rows
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={useRowHeightForLockedRows}
          onChange={setUseRowHeightForLockedRows}
        >
          Use same row height for locked rows
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        lockedRows={lockedRows}
        style={gridStyle}
        rowHeight={45}
        columns={columns}
        dataSource={dataSource}
        useRowHeightForLockedRows={useRowHeightForLockedRows}
        showZebraRows={showZebraRows}
      />
    </div>
  );
}

export default () => <App />

Object|number|() => number
default: undefined

Specifies the colspan for a locked row cell.
It can be an object, with keys corresponding to columns, while values can either be functions or number values.
Beside being an object, it can be a function - which will be used for all columns.
Supporting functions, either as part of objects, or directly as the value for the colspan gives you complete flexibility over the functionality.
When a function is used, it's called like this:
if (typeof colspan === 'function') {
  colspan = colspan(
    {
      column,
      columnIndex,
      row,
      rowIndex,
    },
    computedProps
  );
}
so you have access to both the column being rendered and any other additional props you might need
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 600, marginTop: 10 }

let cities;

const lockedRows = [
  {
    position: 'start',
    render: {
      population: ({ summary }) => <div>Population min: {summary.min}</div>
    },
    country: <b>Nothing to render</b>
  },
  {
    position: 'start',
    render: {
      population: ({ summary }) => <div>Population max: {summary.max}</div>
    }
  },
  {
    position: 'start',
    render: {
      population: ({ summary }) => <div>Population average: {summary.avg}</div>
    }
  },

  {
    position: 'end',
    render: {
      name: (_, computedProps) => {
        return <div>Selected rows: <b>{computedProps.computedSelectedCount}</b></div>
      }
    },
    colspan: {
      name: (_, computedProps) => computedProps.visibleColumns.length
    },
    cellStyle: ({ column }, computedProps) => {
      if (column.name !== 'name'){
        return
      }

      const style = {
        paddingTop: 20,
        paddingBottom: 20
      }

      if (computedProps.computedSelectedCount) {
        style.background = '#ff5b5b'
        style.color = 'white'
      }

      return style
    }
  }
]

const summaryReducer = {
  initialValue: {
    min: Infinity,
    max: 0,
    avg: 0
  },
  reducer: (accumulator, item) => {
    if (item.population) {
      return {
        min: Math.min(accumulator.min, item.population),
        max: Math.max(accumulator.max, item.population),
        avg: accumulator.avg + item.population
      }
    }

    return accumulator
  },
  complete: (accumulator, arr) => {
    return Object.assign({}, accumulator, {
      avg: Math.round(accumulator.avg / arr.length),
    })
  }
}

const columns = [
  { name: 'name', defaultFlex: 1, header: 'City', hideable: false, draggable: false },
  { name: 'country', defaultFlex: 1, header: 'Country'},
  {
    name: 'population',
    type: 'number',
    defaultFlex: 1,
    groupBy: false,
    header: 'Population'
  }
]

const App = () => {
  return (
    <div>
      <h3>Locked rows with custom render and colspan</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        defaultGroupBy={['country']}
        columns={columns}
        dataSource={cities}
        summaryReducer={summaryReducer}
        lockedRows={lockedRows}
      />
    </div>
  );
}

cities = [
  {
    id: 'ny',
    country: 'USA',
    name: 'New York City',
    population: 1000
  },
  {
    id: 'la',
    country: 'USA',
    name: 'Los Angeles',
    population: 150
  },
  {
    id: 'paris',
    country: 'France',
    name: 'Paris',
    population: 2000
  },
  {
    id: 'london',
    name: 'London',
    country: 'UK',
    population: 3000
  },
  {
    id: 'SF',
    name: 'San Francisco',
    country: 'USA',
    population: 3900
  },
  {
    id: 'ly',
    name: 'Lyon',
    country: 'France',
    population: 980
  },
  {
    id: 'ma',
    name: 'Manchester',
    country: 'UK',
    population: 2000
  }
]

export default () => <App />

'start'|'end
default: undefined

Specifies the position of the current locked row, either "start" or "end".
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 550, marginTop: 10 }

const loadData = ({ skip, limit, sortInfo }) => {
  return fetch(DATASET_URL + '?limit=' + limit + '&sortInfo=' + JSON.stringify(sortInfo))
    .then(response => {
      const totalCount = response.headers.get('X-Total-Count');
      return response.json().then(data => {
        return { data, count: totalCount * 1 };
      })
    });
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 100 },
  { name: 'firstName', defaultWidth: 200, header: 'First Name' },
  { name: 'lastName', defaultWidth: 200, header: 'Last Name' },
  { name: 'email', defaultFlex: 1, header: 'Email' }
]

const App = () => {
  const [firstLocked, setFirstLocked] = useState(false);
  const [secondLocked, setSecondLocked] = useState(false);
  const [lastLocked, setLastLocked] = useState(false);

  const dataSource = useCallback(loadData, [])

  const lockedRows = []

  if (firstLocked) {
    lockedRows.push({
      position: 'start',
      render: ({column}, computedProps) => {
        const item = computedProps.data[0]

        return item ? item[column.name] : null
      }
    })
  }
  if (secondLocked) {
    lockedRows.push({
      position: 'start',
      render: ({column}, computedProps) => {
        const item = computedProps.data[1]

        return item ? item[column.name] : null
      }
    })
  }

  if (lastLocked) {
    lockedRows.push({
      position: 'end',
      render: ({column}, computedProps) => {
        const item = computedProps.data[computedProps.data.length - 3]

        return item ? item[column.name] : null
      }
    })

    lockedRows.push({
      position: 'end',
      render: ({column}, computedProps) => {
        const item = computedProps.data[computedProps.data.length - 2]

        return item ? item[column.name] : null
      }
    })

    lockedRows.push({
      position: 'end',
      render: ({column}, computedProps) => {
        const item = computedProps.data[computedProps.data.length - 1]

        return item ? item[column.name] : null
      }
    })
  }

  return (
    <div>
      <h3>Locked rows position demo</h3>

      <div style={{ marginBottom: 20}}>
        <CheckBox checked={firstLocked} onChange={setFirstLocked}>
          Lock row 1 at the top (position="start")
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20}}>
        <CheckBox checked={secondLocked} onChange={setSecondLocked}>
          Lock row 2 at the top (position="start")
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20}}>
        <CheckBox checked={lastLocked} onChange={setLastLocked}>
          Lock last 3 rows at the bottom (position="end")
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        lockedRows={lockedRows}
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}

      />
    </div>
  );
}

export default () => <App />

{[columnId]: ReactNode|() => ReactNode}|ReactNode|() => ReactNode
default: undefined

Specifies what content to render inside locked row cells.
Can be an object with keys corresponding to columns, while values can be functions or ReactNode values. Using a function gives you the flexibility to decide what to render at run-time - for example, the first argument will have a summary property which will hold the value computed via the configured summaryReducer.
Called with two args:
render(
  {
    summary,
    row,
    rowIndex,
    column,
    columnIndex,
  },
  computedProps
);
so in the render function you have access to both column information and the computed props of the grid.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 600, marginTop: 10 }

let cities;

const lockedRows = [
  {
    position: 'start',
    render: {
      name: <b>Nothing to render here</b>,
      population: ({ summary }) => <div>Total population: <b>{summary}</b>.</div>
    }
  }
]

const summaryReducer = {
  initialValue: 0,
  reducer: (accumulator, item) => accumulator + (item.population || 0)
}

const columns = [
  { name: 'name', defaultFlex: 1, header: 'City', },
  { name: 'country', defaultFlex: 1, header: 'Country'},
  {
    name: 'population',
    type: 'number',
    defaultFlex: 1,
    header: 'Population'
  }
]

const App = () => {
  return (
    <div>
      <h3>The population column has a summary - shown in corresponding locked row cell.</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={cities}
        summaryReducer={summaryReducer}
        lockedRows={lockedRows}
      />
    </div>
  );
}

cities = [
  {
    id: 'ny',
    country: 'USA',
    name: 'New York City',
    population: 1000
  },
  {
    id: 'la',
    country: 'USA',
    name: 'Los Angeles',
    population: 150
  },
  {
    id: 'paris',
    country: 'France',
    name: 'Paris',
    population: 2000
  },
  {
    id: 'london',
    name: 'London',
    country: 'UK',
    population: 3000
  },
  {
    id: 'SF',
    name: 'San Francisco',
    country: 'USA',
    population: 3900
  },
  {
    id: 'ly',
    name: 'Lyon',
    country: 'France',
    population: 980
  },
  {
    id: 'ma',
    name: 'Manchester',
    country: 'UK',
    population: 2000
  }
]

export default () => <App />

Number
default: undefined

Controls the max height of <ReactDataGrid /> rows.
This is useful when you want to have constrants on row dimensions, for example when usingrowIndexColumn.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import RadioButtonGroup from '@inovua/reactdatagrid-community/packages/RadioButtonGroup'

import people from './people'

const gridStyle = { minHeight: 550 }

const rowHeights = [
  { label: 'small', value: 25 },
  { label: 'normal', value: 40 },
  { label: 'large', value: 80 }
]

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number' },
  { name: 'name', defaultFlex: 1, minWidth: 80, header: 'Name' },
  { name: 'country', defaultFlex: 1, minWidth: 80, header: 'Country' },
  { name: 'city', defaultFlex: 1, minWidth: 80, header: 'City' },
  { name: 'age', minWidth: 80, type: 'number', header: 'Age' }
]

const App = () => {
  const [rowHeight, setRowHeight] = useState(40);

  return (
    <div>
      <p>Max row height is 50px</p>
      <div style={{ display: 'inline-flex', marginBottom: 20 }}>
        <div style={{ marginRight: 16 }}>
          Select row height
        </div>
        <RadioButtonGroup
          radioOptions={rowHeights}
          radioValue={rowHeight}
          onChange={({ checkedItemValue }) => setRowHeight(checkedItemValue)}
          orientation="horizontal"
        />
      </div>
      <ReactDataGrid
        key={rowHeight}
        idProperty="id"
        style={gridStyle}
        rowHeight={rowHeight}
        columns={columns}
        dataSource={people}
        maxRowHeight={50}
      />
    </div>
  );
}

export default () => <App />

Number
default: 20

Should only be used when the <ReactDataGrid /> is configured to have dynamic row height (rowHeight=null). In this situation, the <ReactDataGrid /> needs a minimum height for rows - configured via the mandatory minRowHeight prop.
Since minRowHeight is used when the<ReactDataGrid /> is configured to have natural row heights, it's important to understand performance issues that can occur. Read more in the Performance and virtualization page.
The value specified by minRowHeight is actually applied to <ReactDataGrid /> cells (and not rows), which dictate the height of <ReactDataGrid /> rows.
The natural DOM height of <ReactDataGrid /> rows can be higher than this, but the closer the average row height is to the value specified by minRowHeight, the better the virtualization performs.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const bigCellStyle = {
  minHeight: 80,
  display: 'flex',
  alignItems: 'center'
}

const columns = [
  { name: 'id', type: 'number', header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 2, header: 'Name', render: ({ rowIndex }) => rowIndex % 2 ? <div style={bigCellStyle}>big cell</div> : 'this has minHeight' },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        minRowHeight={50}
        rowHeight={null}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Specifies whether multiple rows can be expanded at a time.
If you want to be able to expand only one row at a time, specify multiRowExpand=false - in this case, expanding one row will collapse the other.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import Button from '@inovua/reactdatagrid-community/packages/Button'

import people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const defaultExpandedRows = { 1: true }

const renderRowDetails = ({ data, toggleRowExpand }) => {
  return <div style={{ padding: 20}}>
    <h3><Button onClick={toggleRowExpand}>Collapse row</Button></h3>
    <h3>Row details:</h3>
    <table>
      <tbody>
        {Object.keys(data).map(name => {
          return <tr key={name}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id', defaultVisible: false },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  const [multiRowExpand, setMultiRowExpand] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={multiRowExpand}
          onChange={setMultiRowExpand}
        >
          Multi row expand
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        renderRowDetails={renderRowDetails}
        multiRowExpand={multiRowExpand}
        style={gridStyle}
        rowExpandHeight={400}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Enables or disabled multiple cellSelection. Cell selection is multiple selection by default.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [multiSelect, setMultiSelect] = useState(true)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={multiSelect} onChange={setMultiSelect}>
          Enable multiSelect - applies for cells
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        multiSelect={multiSelect}
        defaultCellSelection={{}}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

If true, native browser scrollbars will be used instead of the default custom scrollbars of the ReactDataGrid.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'

import people from './people'

const gridStyle = { minHeight: 300 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultFlex: 1 },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [autoHide, setAutoHide] = useState(false);
  const [alwaysShowTrack, setAlwaysShowTrack] = useState(false);
  const [redBackground, setRedBackground] = useState(false);
  const [customSize, setCustomSize] = useState(false);
  const [customRadius, setCustomRadius] = useState(false);
  const [nativeScroll, setNativeScroll] = useState(false);

  const scrollProps = Object.assign({}, ReactDataGrid.defaultProps.scrollProps, {
    autoHide,
    alwaysShowTrack
  })

  if (customSize) {
    scrollProps.scrollThumbWidth = 15
    scrollProps.scrollThumbOverWidth = 20
  }
  if (customRadius) {
    scrollProps.scrollThumbRadius = 20
  }
  if (redBackground) {
    scrollProps.scrollThumbStyle = {
      background: '#ff7474'
    }
  }

  return (
    <div>
      <h3>Customized scrollbars</h3>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={nativeScroll}
          onChange={setNativeScroll}
        >
          Use native scroll
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && autoHide}
          onChange={setAutoHide}
        >
          Auto-hide scrollbars
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && alwaysShowTrack}
          onChange={setAlwaysShowTrack}
        >
          Always show track
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && redBackground}
          onChange={setRedBackground}
        >
          Red background for scroll thumbs
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && customSize}
          onChange={setCustomSize}
        >
          Custom scrollbar size
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && customRadius}
          onChange={setCustomRadius}
        >
          Custom radius (20px)
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        scrollProps={scrollProps}
        nativeScroll={nativeScroll}
        columns={columns}
        enableKeyboardNavigation={false}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: "/"

The character to be used as node path separator - the <ReactDataGrid /> will assign a unique id (see idProperty) to all nodes based on the path from the root node to the respective node. This id value is built by joining all the parent ids using the / character (as defined by this prop). So, for example, expandedNodes could look like this for a grid: expandedNodes={ 1: true, 3: true, '3/1': true', '3/2/1': true }.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 600 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    nodes: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb'
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb'
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    nodes: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    nodes: [
      {
        id: 1,
        name: 'Email data',
        nodes: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const App = () => {
  const [expandedNodes, setExpandedNodes] = useState({ 3: true, '3#1': true })

  const onExpandedNodesChange = useCallback(({ expandedNodes }) => {
    setExpandedNodes(expandedNodes)
  })

  return (
    <div>
      <p>
        Expanded nodes: {expandedNodes == null ? 'none' : JSON.stringify(expandedNodes, null, 2)}.
      </p>
      <ReactDataGrid
        treeColumn="name"
        expandedNodes={expandedNodes}
        nodePathSeparator="#"
        onExpandedNodesChange={onExpandedNodesChange}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        />
    </div>
  );
}

export default () => <App />

String
default: "nodes"

Specifies the name of the property where child nodes will be found in each node.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const treeData = [
  {
    id: 1,
    name: 'Applications',
    folder: true,
    items: [
      {
        id: 1,
        name: 'App store',
        size: '4.5Mb',
        items: null
      },
      {
        id: 2,
        name: 'iMovie',
        size: '106Mb',
        items: null
      },
      {
        id: 3,
        name: 'IRecall',
        size: '200Mb'
      }
    ]
  },
  {
    id: 2,
    name: 'Documents',
    items: [
      {
        id: 1,
        name: 'Todo.md',
        size: '2Kb'
      },
      {
        id: 2,
        name: 'Calendar.md',
        size: '15.2Kb'
      },
      { id: 3, name: 'Shopping list.csv',size: '20Kb' }
    ]
  },
  {
    id: 3,
    name: '3 Downloads',
    items: [
      {
        id: 1,
        name: 'Email data',
        items: [
          {
            id: 1,
            name: 'Personal.xls',
            size: '100Gb'
          },
          { id: 2, name: 'Work.xls' }
        ]
      },
      { id: 2, name: 'MacRestore.gzip' }
    ]
  }
]

const columns = [
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const defaultExpandedNodes = { 1: true }

const App = () => {
  return (
    <div>
      <p>DataGrid with nodes in "items" prop of each node</p>
      <ReactDataGrid
        nodesProperty="items"
        defaultExpandedNodes={defaultExpandedNodes}
        treeColumn={'name'}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Number[]
default: [5, 10, 20, 50, 100]

Configures the page sizes displayed in the ComboBox displayed inside the pagination toolbar.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 500, marginTop: 10 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'lastName', defaultFlex: 1, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultFlex: 1, header: 'Email' }
]

const loadData = ({ skip, limit, sortInfo }) => {
  return fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    return response.json().then(data=>{
      return { data, count: parseInt(totalCount) };
    })
  })
}

const App = () => {
  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination
        defaultLimit={10}
        pageSizes={[5, 10, 20, 40, 80]}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />