DataGrid API - API
General Props 285
Callback Props 55
Styling Props 36
Methods 49

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

Allows row reordering between groups via drag and drop functionality. By default 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 people from './people';

const gridStyle = {
  minHeight: 750,
};

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

const renderRowReorderProxy = ({data}) => {
  return <div style={{ paddingLeft: 30 }}>ID: {data.id} - Name: {data.name}</div>
}

const App = () => {
  const [defaultGroupBy, setDefaultGroupBy] = useState(['country']);
  const [
    allowRowReorderBetweenGroups,
    setallowRowReorderBetweenGroups,
  ] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          theme="default-dark"
          checked={allowRowReorderBetweenGroups}
          onChange={setallowRowReorderBetweenGroups}
        >
          allowRowReorderBetweenGroups
        </CheckBox>
      </div>

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

export default () => <App />;
             

Bool
default: false

Allows row navigation with Tab key.
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: 400 }

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' },
  { name: 'country', defaultFlex: 1,
    header: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
];

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

const App = () => {
  const [allowRowTabNavigation, setAllowRowTabNavigation] = useState(true);

  return (
    <div>
      <p>Navigate with Tab key</p>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={allowRowTabNavigation}
          onChange={setAllowRowTabNavigation}
        >
          Row Tab Navigation
        </CheckBox>
      </div>

      <TextInput style={{ marginBottom: 20, padding: 5, width: 250 }} type="text" autoFocus placeholder="Hit tab to navigate to grid" />
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        defaultFilterValue={filterValue}
        allowRowTabNavigation={allowRowTabNavigation}
      />
      <TextInput style={{ marginTop: 20, padding: 5, width: 250 }} type="text" defaultValue="Hit shift+tab to navigate to grid" />
    </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.

String
default: "\t"

Specify the separator used when copying to clipboard. The default value is "\t".
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,
    minWidth: 80,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 150,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 150 },
  { name: 'age', header: 'Age', minWidth: 100, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const App = () => {
  const [enableClipboard, setEnableClipboard] = useState(true);
  const [
    copySpreadsheetCompatibleString,
    setCopySpreadsheetCompatibleString,
  ] = useState(true);

  return (
    <div>
      <h3>Grid with clipboard separator</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableClipboard}
          onChange={setEnableClipboard}
        >Enable clipboard</CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={copySpreadsheetCompatibleString}
          onChange={setCopySpreadsheetCompatibleString}
        >
          Copy spreadsheet compatible string
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard={enableClipboard}
        defaultCellSelection={{}}
        style={gridStyle}
        columns={columns}
        dataSource={people}
        clipboardSeparator=","
        copySpreadsheetCompatibleString={copySpreadsheetCompatibleString}
      />
    </div>
  );
};

export default () => <App />;

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 + 1] && columns[column.computedVisibleIndex + 2].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 />

'asc' | 'desc'
default: undefined

When defaultSortingDirection is set to 'asc', the default sorting behaviour is to sort in ascending order, i.e. at the first click on the header cell, the column will be sorted in ascending order. When defaultSortingDirection is set to 'desc', the default behavior is to sort in descending order.
import React from 'react';

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

const gridStyle = { minHeight: 550 };

const columns = [
  { name: 'id', header: 'Id', defaultWidth: 80, defaultVisible: false },
  {
    name: 'name',
    sortable: false,
    header: 'Name (column not sortable)',
    defaultFlex: 1,
  },
  { 
    name: 'age', 
    header: 'Age', 
    type: 'number', 
    defaultFlex: 1,
    defaultSortingDirection: 'desc'
  },
];

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

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

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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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
default: undefined

Controls whether the filter context menu should be displayed or not for a specific column.
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 SelectFilter from '@inovua/reactdatagrid-community/SelectFilter'
import DateFilter from '@inovua/reactdatagrid-community/DateFilter'

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

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

const gridStyle = { minHeight: 600 }

const COUNTRIES = {
  ca: 'Canada',
  uk: 'United Kingdom',
  usa: 'United States of America'
}

const countries = people.reduce((countries, p) => {
  if (countries.filter(c => c.id == p.country).length) {
    return countries
  }
  countries.push({
    id: p.country,
    label: COUNTRIES[p.country] || p.country
  })

  return countries
}, []);

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: '' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 },
  { name: 'city', operator: 'startsWith', type: 'string', value: '' },
  {
    name: 'birthDate',
    operator: 'before',
    type: 'date',
    value: ''
  },
  { name: 'country', operator: 'eq', type: 'select', value: 'ca' }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1, enableColumnFilterContextMenu: true },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number', filterEditor: NumberFilter },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    filterEditor: SelectFilter,
    filterEditorProps: {
      placeholder: 'All',
      dataSource: countries
    },
    render: ({ value })=> flags[value]? flags[value]: value
  },
  {
    name: 'birthDate',
    header: 'Bith date',
    defualtFlex: 1,
    minWidth: 200,
    enableColumnFilterContextMenu: false,
    filterEditor: DateFilter,
    filterEditorProps: (props, { index }) => {
      // for range and notinrange operators, the index is 1 for the after field
      return {
        dateFormat: 'MM-DD-YYYY',
        cancelButton: false,
        highlightWeekends: false,
        placeholder: index == 1 ? 'Created date is before...': 'Created date is after...'
      }
    },
    render: ({ value, cellProps }) => {
      return moment(value).format('MM-DD-YYYY')
    }
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
];

const App = () => {
  const [enableColumnFilterContextMenu, setEnableColumnFilterContextMenu] = useState(true);

  return (
    <div>
      <h3>Grid with filter context menu control</h3>

      <p>
        The 'name' column has "enableColumnFilterContextMenu" setted to 'true' 
        and 'birthDate' has "enableColumnFilterContextMenu" setted to 'false' 
        at the column level.
      </p>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableColumnFilterContextMenu}
          onChange={setEnableColumnFilterContextMenu}
        >Enable column filter context menu</CheckBox>
      </div>

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

export default () => <App />

Bool
default: undefined

Controls whether a column or a number of columns has hover enabled 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';
import flags from './flags';

const gridStyle = { minHeight: 550 };
            
const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultWidth: 60,
    type: 'number',
  },
  { name: 'name', header: 'Name', defaultWidth: 100 },
  {
    name: 'country',
    header: 'Country',
    defaultWidth: 100,
    render: ({ value }: { value: string }) =>
      flags[value] ? flags[value] : value,
  },
  {
    name: 'city',
    header: 'City',
    defaultWidth: 120,
    enableColumnHover: false
  },
  {
    name: 'age',
    header: 'Age',
    defaultWidth: 100,
    type: 'number',
    enableColumnHover: true
  },
];

const App = () => {
  const [enableColumnHover, setEnableColumnHover] = useState(true)

  return (
    <div>
      <h3>Grid with hover disabled on 'city' column and 'age' column enabled</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableColumnHover}
          onChange={setEnableColumnHover}
        >Enable column hover</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        enableColumnHover={enableColumnHover}
      />
    </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 />

Fn({ className: String, filterValue: String })
default: undefined

Specifies a custom render function for the filter settings icon.
import React from 'react'

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

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

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

const gridStyle = { minHeight: 600 }

const filterIcon = className => {
  return (
    <svg
      className={className}
      enable-background="new 0 0 24 24"
      height="24px"
      viewBox="0 0 24 24"
      width="24px"
    >
      <g>
        <path d="M0,0h24 M24,24H0" fill="none" />
        <path d="M7,6h10l-5.01,6.3L7,6z M4.25,5.61C6.27,8.2,10,13,10,13v6c0,0.55,0.45,1,1,1h2c0.55,0,1-0.45,1-1v-6 c0,0,3.72-4.8,5.74-7.39C20.25,4.95,19.78,4,18.95,4H5.04C4.21,4,3.74,4.95,4.25,5.61z" />
        <path d="M0,0h24v24H0V0z" fill="none" />
      </g>
    </svg>
  );
};

const COUNTRIES = {
  ca: 'Canada',
  uk: 'United Kingdom',
  usa: 'United States of America'
}

const countries = people.reduce((countries, p) => {
  if (countries.filter(c => c.id == p.country).length) {
    return countries
  }
  countries.push({
    id: p.country,
    label: COUNTRIES[p.country] || p.country
  })

  return countries
}, []);

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: '' },
  { name: 'age', operator: 'gte', type: 'number', value: null },
  { name: 'city', operator: 'startsWith', type: 'string', value: '' },
  {
    name: 'birthDate',
    operator: 'before',
    type: 'date',
    value: ''
  },
  { name: 'country', operator: 'eq', type: 'select', value: null }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { 
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    filterEditorProps: {
      placeholder: 'Name',
      renderSettings: ({ className }) => filterIcon(className)
    },
  },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number', filterEditor: NumberFilter },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    filterEditor: SelectFilter,
    filterEditorProps: {
      placeholder: 'All',
      dataSource: countries,
      renderSettings: ({ className }) => filterIcon(className)
    },
    render: ({ value })=> flags[value]? flags[value]: value
  },
  {
    name: 'birthDate',
    header: 'Bith date',
    defualtFlex: 1,
    minWidth: 200,
    filterEditor: DateFilter,
    filterEditorProps: (props, { index }) => {
      // for range and notinrange operators, the index is 1 for the after field
      return {
        dateFormat: 'MM-DD-YYYY',
        cancelButton: false,
        highlightWeekends: false,
        renderSettings: ({ className }) => filterIcon(className),
        placeholder: index == 1 ? 'Created date is before...': 'Created date is after...'
      }
    },
    render: ({ value, cellProps }) => {
      return moment(value).format('MM-DD-YYYY')
    }
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
];

const App = () => {
  console.log('people', people)
  return (
    <div>
      <h3>Grid with custom filter icon on Name and Country columns</h3>
      <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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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 Arrow from './Arrow'
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}>
    {direction === -1 ? <Arrow type="activeUp" style={arrowStyle} /> : <Arrow type="up" style={arrowStyle} />}
    {direction === 1 ? <Arrow type="activeDown" style={arrowStyle} /> : <Arrow type="down" 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, rowId }) => {
    const data = [...dataSource];
    data[rowId] = Object.assign({}, data[rowId], {[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 Arrow from './Arrow'
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}>
    {direction === -1 ? <Arrow type="activeUp" style={arrowStyle} /> : <Arrow type="up" style={arrowStyle} />}
    {direction === 1 ? <Arrow type="activeDown" style={arrowStyle} /> : <Arrow type="down" 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

A setter for the cell value.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import flags from './flags'

const gridStyle = { height: 300 }

const columns = [
  { name: 'firstName', defaultFlex: 1, header: 'First Name' },
  {
    name: 'lastName',
    defaultFlex: 1,
    header: 'Last Name',
    setValue({ value }: { value: string }) {
      if (value === 'Fil' || value === 'Twain') {
        return 'Johnny';
      }
      return value;
    },
  },
  {
    name: 'country',
    header: 'Country',
    defaultWidth: 100,
    textAlign: 'center',
    render: ({ value }: { value: string }) => 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>
    ),
    setValue({ value }) {
      if (value > 16 && value < 21) {
        return 'teenager';
      }
      if (value >= 21 && value < 30) {
        return 'young';
      }
      return 'adult';
    },
  },
];

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 },
  { firstName: 'Karl', lastName: 'May', country: 'usa', age: 19, id: 4 }
]

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

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 />

Bool
default: false

When true, it copies to clipboard a string compatible with spreadsheet editors. The default separator is '\t', see clipboardSeparator.
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,
    minWidth: 80,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 150,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 150 },
  { name: 'age', header: 'Age', minWidth: 100, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const App = () => {
  const [enableClipboard, setEnableClipboard] = useState(true);
  const [
    copySpreadsheetCompatibleString,
    setCopySpreadsheetCompatibleString,
  ] = useState(true);

  return (
    <div>
      <h3>Grid with copy spreadsheet compatible string</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableClipboard}
          onChange={setEnableClipboard}
        >Enable clipboard</CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={copySpreadsheetCompatibleString}
          onChange={setCopySpreadsheetCompatibleString}
        >
          Copy spreadsheet compatible string
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard={enableClipboard}
        defaultCellSelection={{}}
        style={gridStyle}
        columns={columns}
        dataSource={people}
        copySpreadsheetCompatibleString={copySpreadsheetCompatibleString}
      />
    </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 />

'asc' | 'desc'
default: undefined

When defaultSortingDirection is set to 'asc', the default sorting behaviour is to sort in ascending order, i.e. at the first click on the header cell, the column will be sorted in ascending order. When defaultSortingDirection is set to 'desc', the default behavior is to sort in descending order.
import React from 'react';

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

const gridStyle = { minHeight: 550 };

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

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

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

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 />

Object
default: undefined

Specifies the disabled rows in the <ReactDataGrid />.
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, 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 disabledRows = {
  3: true,
  4: true,
  7: true,
}

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

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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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: false

When bulk update is enabled and cells are selected via selection box, the value of the active cell is copied to the selected cells.
In order for bulk update to work, cellSelection or defaultCellSelection must be enabled.
import React, { useCallback, useState } from 'react';

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

import people from './people';

const gridStyle = { minHeight: 350 };

const minWidth: number = 160;
const columns = [
  {
    name: 'id',
    header: 'ID',
    type: 'number',
    defaultWidth: 80,
    defaultVisible: false,
  },
  { name: 'firstName', header: 'First Name', flex: 1, minWidth },
  { name: 'city', header: 'City', flex: 1, minWidth },
  { name: 'email', header: 'Email', flex: 1, minWidth },
  { name: 'country', header: 'Country', flex: 1, minWidth },
  { name: 'age', header: 'Age', type: 'number', flex: 1, minWidth },
  {
    name: 'student',
    header: 'Student',
    render: ({ value }) => {
      if (typeof value === 'boolean') {
        return value ? 'Yes' : 'No';
      }
      return value;
    },
    minWidth,
  },
  { name: 'birthDate', header: 'Birth Date', flex: 1, minWidth },
];

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

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

      setDataSource(data);
    },
    []
  );

  return (
    <div>
      <DataGrid
        columns={columns}
        idProperty="id"
        style={gridStyle}
        dataSource={dataSource}
        defaultCellSelection={{}}
        multiSelect
        enableCellBulkUpdate
        editable
        onEditComplete={onEditComplete}
      />
    </div>
  );
};
export default () => <App />;

Bool
default: false

When true, enables copy-paste active row or selected cells to/from clipboard.
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,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const App = () => {
  const [enableClipboard, setEnableClipboard] = useState(true)

  return (
    <div>
      <h3>Grid with copy/paste the active row</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableClipboard}
          onChange={setEnableClipboard}
        >Enable clipboard</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard={enableClipboard}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Bool
default: undefined

When enableClipboardForEditableCellsOnly is true, enables clipboard only for editable cells.
import React, { useState, useCallback } from 'react';
import '@inovua/reactdatagrid-enterprise/index.css';
import ReactDataGrid from '@inovua/reactdatagrid-enterprise';

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

const gridStyle = { minHeight: 550 };

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

  {
    name: 'city',
    header: 'City',
    defaultFlex: 1,
    minWidth: 300,
    editable: false,
  },
  {
    name: 'age',
    header: 'Age',
    minWidth: 150,
    type: 'number',
    editable: true,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    render: ({ value }) => flags[value] ? flags[value] : value,
  },
];

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

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

      setDataSource(data);
    },
    [dataSource]
  );

  const onCopySelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  const onPasteSelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  return (
    <div>
      <h3>Grid with inline edit</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable={true}
        columns={columns}
        dataSource={dataSource}
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        enableClipboard
        onCopySelectedCellsChange={onCopySelectedCellsChange}
        onPasteSelectedCellsChange={onPasteSelectedCellsChange}
        enableClipboardForEditableCellsOnly
      />
    </div>
  );
};

export default () => <App />;

Bool
default: true

Enables the column auto size on the grid.
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';
import Button from '@inovua/reactdatagrid-community/packages/Button';
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox';

const gridStyle = { minHeight: 550 };

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

const App = () => {
  const [gridRef, setGridRef] = useState(null);
  const [enableColumnAutosize, setEnableColumnAutosize] = useState(true);

  return (
    <div>
      <h3>Grid with colums autosize</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={enableColumnAutosize} onChange={setEnableColumnAutosize}>Enable column autosize</CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <Button
          onClick={() => {
            if (gridRef && gridRef.current.setColumnSizesToFit) {
              gridRef.current.setColumnSizesToFit();
            }
          }}
        >
          Set column sizes to fit
        </Button>
      </div>

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

export default () => <App />;

Bool
default: true

Controls whether the column filter context menu should be displayed or not. Default to true.
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 SelectFilter from '@inovua/reactdatagrid-community/SelectFilter'
import DateFilter from '@inovua/reactdatagrid-community/DateFilter'

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

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

const gridStyle = { minHeight: 600 }

const COUNTRIES = {
  ca: 'Canada',
  uk: 'United Kingdom',
  usa: 'United States of America'
}

const countries = people.reduce((countries, p) => {
  if (countries.filter(c => c.id == p.country).length) {
    return countries
  }
  countries.push({
    id: p.country,
    label: COUNTRIES[p.country] || p.country
  })

  return countries
}, []);

const filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: '' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 },
  { name: 'city', operator: 'startsWith', type: 'string', value: '' },
  {
    name: 'birthDate',
    operator: 'before',
    type: 'date',
    value: ''
  },
  { name: 'country', operator: 'eq', type: 'select', value: 'ca' }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1, enableColumnFilterContextMenu: true },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number', filterEditor: NumberFilter },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    filterEditor: SelectFilter,
    filterEditorProps: {
      placeholder: 'All',
      dataSource: countries
    },
    render: ({ value })=> flags[value]? flags[value]: value
  },
  {
    name: 'birthDate',
    header: 'Bith date',
    defualtFlex: 1,
    minWidth: 200,
    enableColumnFilterContextMenu: false,
    filterEditor: DateFilter,
    filterEditorProps: (props, { index }) => {
      // for range and notinrange operators, the index is 1 for the after field
      return {
        dateFormat: 'MM-DD-YYYY',
        cancelButton: false,
        highlightWeekends: false,
        placeholder: index == 1 ? 'Created date is before...': 'Created date is after...'
      }
    },
    render: ({ value, cellProps }) => {
      return moment(value).format('MM-DD-YYYY')
    }
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
];

const App = () => {
  const [enableColumnFilterContextMenu, setEnableColumnFilterContextMenu] = useState(true);

  return (
    <div>
      <h3>Grid with filter context menu control</h3>

      <p>
        The 'name' column has "enableColumnFilterContextMenu" setted to 'true' 
        and 'birthDate' has "enableColumnFilterContextMenu" setted to 'false' 
        at the column level.
      </p>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableColumnFilterContextMenu}
          onChange={setEnableColumnFilterContextMenu}
        >Enable column filter context menu</CheckBox>
      </div>

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

export default () => <App />

Bool
default: undefined

Controls whether the hover on columns is enabled 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';
import flags from './flags';

const gridStyle = { minHeight: 550 };
            
const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultWidth: 60,
    type: 'number',
  },
  { name: 'name', header: 'Name', defaultWidth: 100 },
  {
    name: 'country',
    header: 'Country',
    defaultWidth: 100,
    render: ({ value }: { value: string }) =>
      flags[value] ? flags[value] : value,
  },
  {
    name: 'city',
    header: 'City',
    defaultWidth: 120,
  },
  {
    name: 'age',
    header: 'Age',
    defaultWidth: 100,
    type: 'number',
  },
];

const App = () => {
  const [enableColumnHover, setEnableColumnHover] = useState(true)

  return (
    <div>
      <h3>Grid with column hover enabled</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableColumnHover}
          onChange={setEnableColumnHover}
        >Enable column hover</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        enableColumnHover={enableColumnHover}
      />
    </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 />

Bool
default: false

Enables row reorder on tree grid.
For enabling row reorder on tree grid, rowReorderColumn and enableTreeRowReorder should both be true.
Be aware that row reorder on tree grid works only if generatedIdFromPath is true, because the way that the grid finds drag row and drop row is from path generated by initial nodes ids.
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 gridStyle = { minHeight: 750 };

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' },
    ],
  },
  { id: 4, name: 'Movies' },
];

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

const App = () => {
  const [rowReorderColumn, setRowReorderColumn] = useState(true);
  const [enableTreeRowReorder, setEnableTreeRowReorder] = useState(true);

  return (
    <div>
      <h3>TreeGrid with row reorder</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={rowReorderColumn} onChange={setRowReorderColumn}>
          rowReorderColumn
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={enableTreeRowReorder} onChange={setEnableTreeRowReorder}>
          enableTreeRowReorder
        </CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        theme="default-dark"
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        defaultExpandedNodes={{ 1: true, 2: true, 3: true, '3/1': true }}
        rowReorderColumn={rowReorderColumn}
        enableTreeRowReorder={enableTreeRowReorder}
      />
    </div>
  );
};

export default () => <App />;

Bool
default: true

Allows changing the leaf indentation via drag and drop functionality by dragging the proxy horizontally left or right. If the proxy is dragged to the right, the leaf indentation is increased by treeNestingSize ammount. Same if the proxy is dragged to the left, the indentation is decreased by treeNestingSize ammount. By default is 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';

const gridStyle = { minHeight: 750 };

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' },
    ],
  },
  { id: 4, name: 'Movies' },
];

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

const App = () => {
  const [rowReorderColumn, setRowReorderColumn] = useState(true);
  const [enableTreeRowReorder, setEnableTreeRowReorder] = useState(true);
  const [enableTreeRowReorderNestingChange, setEnableTreeRowReorderNestingChange] = useState(true);

  return (
    <div>
      <h3>TreeGrid with row reorder</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={rowReorderColumn} onChange={setRowReorderColumn}>
          rowReorderColumn
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={enableTreeRowReorder} onChange={setEnableTreeRowReorder}>
          enableTreeRowReorder
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={enableTreeRowReorderNestingChange} onChange={setEnableTreeRowReorderNestingChange}>
        enableTreeRowReorderNestingChange
        </CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        theme="default-dark"
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        defaultExpandedNodes={{ 1: true, 2: true, 3: true, '3/1': true }}
        rowReorderColumn={rowReorderColumn}
        enableTreeRowReorder={enableTreeRowReorder}
        enableTreeRowReorderNestingChange={enableTreeRowReorderNestingChange}
      />
    </div>
  );
};

export default () => <App />;

Bool
default: true

If enableTreeRowReorderParentChange is true, allows droppind a row to another parent. By default is 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';

const gridStyle = { minHeight: 750 };

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' },
    ],
  },
  { id: 4, name: 'Movies' },
];

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

const App = () => {
  const [rowReorderColumn, setRowReorderColumn] = useState(true);
  const [enableTreeRowReorder, setEnableTreeRowReorder] = useState(true);
  const [enableTreeRowReorderParentChange, setEnableTreeRowReorderParentChange] = useState(true);

  return (
    <div>
      <h3>TreeGrid with row reorder</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={rowReorderColumn} onChange={setRowReorderColumn}>
          rowReorderColumn
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={enableTreeRowReorder} onChange={setEnableTreeRowReorder}>
          enableTreeRowReorder
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={enableTreeRowReorderParentChange} onChange={setEnableTreeRowReorderParentChange}>
        enableTreeRowReorderParentChange
        </CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        theme="default-dark"
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        defaultExpandedNodes={{ 1: true, 2: true, 3: true, '3/1': true }}
        rowReorderColumn={rowReorderColumn}
        enableTreeRowReorder={enableTreeRowReorder}
        enableTreeRowReorderParentChange={enableTreeRowReorderParentChange}
      />
    </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 />

Bool
default: false

Allow expand/collapse tree node on mouse down.
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 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', header: 'Name', defaultFlex: 1 },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const defaultExpandedNodes = { 1: true }

const App = () => {
  const [showTools, setShowTools] = useState(true);
  const [expandOnMouseDown, setExpandOnMouseDown] = useState(true);

  const renderCollapseTool = ({ domProps, size }) => {
    const style = Object.assign(domProps.style, { fill: 'red' });
    return (
      <svg
        {...domProps}
        height={size}
        viewBox="0 0 24 24"
        width={size}
        style={style}
      >
        <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
      </svg>
    );
  };

  const renderExpandTool = ({ domProps, size }) => {
    const style = Object.assign(domProps.style, { fill: 'red' });
    return (
      <svg
        {...domProps}
        height={size}
        viewBox="0 0 24 24"
        width={size}
        style={style}
      >
        <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" />
      </svg>
    );
  };

    return (
    <div>
      <h3>TreeGrid with exand/collapse on mouse down</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={showTools} onChange={setShowTools}>Show tools</CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={expandOnMouseDown} onChange={setExpandOnMouseDown}>Enable expand/collapse node on mouse down</CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        renderTreeCollapseTool={showTools ? renderCollapseTool : null}
        renderTreeExpandTool={showTools ? renderExpandTool : null}
        expandOnMouseDown={expandOnMouseDown}
      />
    </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: '',
    operators: [
      {
        name: 'europe',
        fn: ({ value, filterValue, data }) => {
          const isInEurope = value != 'usa' && value != 'ca'

          return filterValue === 'true' ?
            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>
If the dataSource contains nested objects, the <ReactDataGrid /> rows can be uniquely identified by the nested objects indentifier (the id of nested objects, for example).
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const dataSource = [
  {
    id: 0,
    person: {
      personId: 0,
      name: 'Amanda Soaresz',
      personalData: { age: 35, location: 'Rome' },
    },
  },
  {
    id: 1,
    person: {
      personId: 1,
      name: 'Mary Adamson',
      personalData: { age: 25, location: 'Madrid' },
    },
  },
  {
    id: 2,
    person: {
      personId: 2,
      name: 'Robert Fil',
      personalData: { age: 27, location: 'Seattle' },
    },
  },
  {
    id: 3,
    person: {
      personId: 3,
      name: 'Roger Bob',
      personalData: { age: 81, location: 'Frankfurt' },
    },
  },
  {
    id: 4,
    person: {
      personId: 4,
      name: 'Billary Konwik',
      personalData: { age: 18, location: 'Vienna' },
    },
  },
  {
    id: 5,
    person: {
      personId: 5,
      name: 'Bob Marc',
      personalData: { age: 18, location: 'Brussels' },
    },
  },
  {
    id: 6,
    person: {
      personId: 6,
      name: 'Matthew Richardson',
      personalData: { age: 54, location: 'Amsterdam' },
    },
  },
  {
    id: 7,
    person: {
      personId: 7,
      name: 'Richy Peterson',
      personalData: { age: 54, location: 'Salzburg' },
    },
  },
];

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    type: 'number',
    defaultWidth: 80,
  },
  {
    name: 'person',
    header: 'Person',
    defaultWidth: 200,
    render: ({ data }) => {
      return <span>{data.person.name}</span>;
    },
  },
  {
    name: 'person.personalData.age',
    header: 'Age',
    defaultWidth: 100,
    render: ({ data }) => <span>{data.person.personalData.age}</span>,
  },
  {
    name: 'person.personalData.location',
    header: 'Location',
    defaultWidth: 120,
    render: ({ data }) => {
      return <span>{data.person.personalData.location}</span>;
    },
  },
];

const gridStyle = {
  minHeight: 450
}

export default () => <div>
  <ReactDataGrid
    idProperty="person.personId"
    columns={columns}
    dataSource={dataSource}
    style={gridStyle}
  />
</div>

String
default: "."

The character used to separate id properties if the id is nested in the dataSource objects (see idProperty).
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const dataSource = [
  {
    id: 0,
    person: {
      personId: 0,
      name: 'Amanda Soaresz',
      personalData: { age: 35, location: 'Rome' },
    },
  },
  {
    id: 1,
    person: {
      personId: 1,
      name: 'Mary Adamson',
      personalData: { age: 25, location: 'Madrid' },
    },
  },
  {
    id: 2,
    person: {
      personId: 2,
      name: 'Robert Fil',
      personalData: { age: 27, location: 'Seattle' },
    },
  },
  {
    id: 3,
    person: {
      personId: 3,
      name: 'Roger Bob',
      personalData: { age: 81, location: 'Frankfurt' },
    },
  },
  {
    id: 4,
    person: {
      personId: 4,
      name: 'Billary Konwik',
      personalData: { age: 18, location: 'Vienna' },
    },
  },
  {
    id: 5,
    person: {
      personId: 5,
      name: 'Bob Marc',
      personalData: { age: 18, location: 'Brussels' },
    },
  },
  {
    id: 6,
    person: {
      personId: 6,
      name: 'Matthew Richardson',
      personalData: { age: 54, location: 'Amsterdam' },
    },
  },
  {
    id: 7,
    person: {
      personId: 7,
      name: 'Richy Peterson',
      personalData: { age: 54, location: 'Salzburg' },
    },
  },
];

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    type: 'number',
    defaultWidth: 80,
  },
  {
    name: 'person',
    header: 'Person',
    defaultWidth: 200,
    render: ({ data }) => {
      return <span>{data.person.name}</span>;
    },
  },
  {
    name: 'person.personalData.age',
    header: 'Age',
    defaultWidth: 100,
    render: ({ data }) => <span>{data.person.personalData.age}</span>,
  },
  {
    name: 'person.personalData.location',
    header: 'Location',
    defaultWidth: 120,
    render: ({ data }) => {
      return <span>{data.person.personalData.location}</span>;
    },
  },
];

const gridStyle = {
  minHeight: 450
}

export default () => <div>
  <ReactDataGrid
    idProperty="person.personId"
    idPropertySeparator="-"
    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, rowId }) => {
    const data = [...dataSource];
    data[rowId][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 {rowHeight}px</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 />

Boolean|String
default: undefined

Configured pagination for the <ReactDataGrid /> - supports both local and remote pagination.
Specify pagination=true to have the pagination toolbar displayed. By default, if local or remote pagination is not explicitly specified (by using pagination="local" or pagination="remote"), the <ReactDataGrid /> will figure out if it should use local or remote pagination depending on how the dataSource is defined - if it's a remote dataSource (a Promise or a function) or a local one (an array).
If you want to be explicit about local pagination, use pagination="local"
If you want to explicitly specify remote pagination use pagination="remote".
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', 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 [pagination, setPagination] = useState(true);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={pagination} onChange={setPagination}>
          Pagination
        </CheckBox>
      </div>
      <ReactDataGrid
        key={'grid-' + pagination}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination={pagination}
        sortable={false}
        dataSource={dataSource}
        defaultLimit={10}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

Using paginationProps you can customize any prop that PaginationToolbar accepts and tweak it to fit your own specific configuration needs.
Below is a list of most used props from PaginationToolbar:
  • limit - used to configure the page size for the <ReactDataGrid />.
  • skip - used to control skip value for the <ReactDataGrid />.
  • defaultLimit - used to configure the default page size for the <ReactDataGrid />.
  • defaultSkip - used to control the default skip value for the <ReactDataGrid />.
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 empty = () => null

const buttonStyle = { marginRight: 8 }

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 [skip, setSkip] = useState(10);
  const [limit, setLimit] = useState(10);
  const [sortInfo, setSortInfo] = useState(null);
  const [loading, setLoading] = useState(false);

  const dataSource = useCallback(loadData, [])

  const updateSkip = useCallback((amount) => {
    return () => {
      let newSkip = skip + amount
      newSkip = Math.min(newSkip, 100)
      newSkip = Math.max(newSkip, 0)

      setSkip(newSkip);
    }
  }, [skip])

  const updateLimit = useCallback((amount) => {
    return () => {
      let newLimit = limit + amount
      newLimit = Math.min(newLimit, 100)
      newLimit = Math.max(newLimit, 0)

      setLimit(newLimit);
    }
  }, [limit])

  const sortByHandle = useCallback((colName, dir) => {
    return () => {
      setSortInfo({ name: colName, dir });
    }
  }, [])

  const disabled = loading || Array.isArray(dataSource)

  return (
    <div>
      <p>Current skip: {skip}. Current limit: {limit}.</p>
      <div style={{ marginBottom: 20 }}>
        <Button style={buttonStyle} onClick={updateSkip(10)} disabled={disabled}>skip += 10</Button>
        <Button style={buttonStyle} onClick={updateSkip(-10)} disabled={disabled || skip==0}>skip -= 10</Button>
        <Button style={buttonStyle} onClick={updateLimit(10)} disabled={disabled}>limit += 10</Button>
        <Button onClick={updateLimit(-10)} disabled={disabled  || limit<=10}>limit -= 10</Button>
      </div>
      <div style={{ marginBottom: 20 }}>
        <Button style={buttonStyle} onClick={sortByHandle("firstName", 1)} disabled={disabled}>sort by First Name, ASC</Button>
        <Button onClick={sortByHandle("lastName", -1)} disabled={disabled}>sort by Last Name, DESC</Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        sortInfo={sortInfo}
        onSortInfoChange={setSortInfo}
        pagination
        limit={limit}
        skip={skip}
        onLimitChange={setLimit}
        onSkipChange={setSkip}
        renderPaginationToolbar={empty}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Array<string|{name,summaryReducer,summaryColumn}>
default: undefined

Enables pivot mode on the grid.
To enable pivot mode, specify pivot=[] or specify the list of columns to pivot by (eg: pivot=["sport",{ "name": "category" }]- an array of column names (it can also be an array of objects, where each should have a name property - the name or the id of a column to be used for pivoting).
In order for a column to be displayed when pivot is enabled, the column needs to specify a column.groupSummaryReducer prop, so it can aggregate values, in order to display them in the pivoted cells.
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: 500, marginTop: 10 }

const dataSource = () =>
  Promise.resolve([
    {
      country: 'USA',
      continent: 'North America',
      year: 2000,
      sport: 'footbal',
      gold: 2,
      silver: 3,
      bronze: 1,
      team: 'red',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2000,
      sport: 'footbal',
      gold: 1,
      silver: 4,
      bronze: 2,
      team: 'blue',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2000,
      sport: 'swim',
      gold: 6,
      silver: 4,
      bronze: 2,
      team: 'swim-blue',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2002,
      sport: 'footbal',
      gold: 1,
      silver: 4,
      bronze: 2,
      team: 'star',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2002,
      sport: 'swim',
      gold: 10,
      silver: 4,
      bronze: 2,
      team: 'swimmers',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2003,
      sport: 'swim',
      gold: 10,
      silver: 4,
      bronze: 2,
      team: 'swimmers',
    },
    {
      country: 'France',
      continent: 'Europe',
      year: 2003,
      sport: 'footbal',
      gold: 1,
      silver: 4,
      bronze: 2,
      team: 'paris-team',
    },
    {
      country: 'France',
      continent: 'Europe',
      year: 2004,
      sport: 'swim',
      gold: 3,
      silver: 1,
      bronze: 1,
      team: 'paris-team',
    },
    {
      country: 'France',
      continent: 'Europe',
      year: 2005,
      sport: 'swim',
      gold: 3,
      silver: 1,
      bronze: 1,
      team: 'toulouse-team',
    },
  ]);

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

  const countReducer = {
    initialValue: 0,
    reducer: (v: number) => v + 1,
  };

  const columns = [
    {
      name: 'country',
      defaultFlex: 1,
      header: 'Country'
    },
    {
      name: 'continent',
      defaultFlex: 1,
      header: 'Continent'
    },
    {
      name: 'year',
      type: 'number',
      header: 'Year',
    },
    {
      name: 'gold',
      groupSummaryReducer: sumReducer,
      render: ({ value }) => (value || 0) + " gold",
      renderSummary: ({ value, data }) => (value || 0) + " gold medals",
      header: 'Gold medals'
    },
    {
      name: 'silver',
      groupSummaryReducer: sumReducer,
      header: 'Silver medals'
    },
    {
      name: 'bronze',
      groupSummaryReducer: sumReducer,
      header: 'Bronze medals'
    },
    {
      name: 'sport',
      header: 'Sport'
    },
  ];

const App = () => {
  const [enablePivot, setEnablePivot] = useState(true);
  const [groupBy, setGroupBy] = useState(['continent','country','year']);
  const [pivot, setPivot] = useState(['sport']);

  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, ['continent','country','year'])
  }, groupBy)

  const updatePivot = useCallback((keys) => {
    updateArray(pivot, setPivot, keys)
  }, [pivot])

  return (
    <div>
      <h3>DataGrid with pivot example</h3>
      <div style={{ marginTop: 20}}>
        <CheckBox
          checked={enablePivot}
          onChange={setEnablePivot}
        >
          Enable pivot
        </CheckBox>
      </div>
      <div style={{ marginTop: 20}}>
        <CheckBox
          disabled={!enablePivot}
          checked={pivot.indexOf('sport') !== -1}
          onChange={checked => updatePivot({ sport: checked})}
        >
          Pivot by <b>sport</b> column values
        </CheckBox>
      </div>

      <div style={{ marginTop: 20}}>
        <CheckBox
          checked={groupBy.indexOf('continent') !== -1}
          onChange={checked => updateGroupBy({ continent: checked })}
        >
          Group by continent
        </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('year') !== -1}
          onChange={checked => updateGroupBy({ year: checked})}
        >
          Group by year
        </CheckBox>
      </div>

      <ReactDataGrid
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}

        pivot={enablePivot? pivot: null}
        groupBy={groupBy}

        groupNestingSize={40}
        onGroupByChange={setGroupBy}

        groupSummaryReducer={countReducer}
        groupColumn={{
          defaultFlex: 1,
          minWidth: 250,
          renderGroupValue: ({ value, groupSummary }) => (
            <React.Fragment>
              {value} ({groupSummary} records)
            </React.Fragment>
          ),
        }}
      />
    </div>
  )
}

export default () => <App />

Array<string|{name,summaryReducer,summaryColumn}>
default: undefined

Specifies the name or the id of a column to be used for pivoting).
In order for a column to be displayed when pivot is enabled, the column needs to specify a column.groupSummaryReducer prop, so it can aggregate values, in order to display them in the pivoted cells.
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: 500, marginTop: 10 }

const dataSource = () =>
  Promise.resolve([
    {
      country: 'USA',
      continent: 'North America',
      year: 2000,
      sport: 'footbal',
      gold: 2,
      silver: 3,
      bronze: 1,
      team: 'red',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2000,
      sport: 'footbal',
      gold: 1,
      silver: 4,
      bronze: 2,
      team: 'blue',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2000,
      sport: 'swim',
      gold: 6,
      silver: 4,
      bronze: 2,
      team: 'swim-blue',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2002,
      sport: 'footbal',
      gold: 1,
      silver: 4,
      bronze: 2,
      team: 'star',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2002,
      sport: 'swim',
      gold: 10,
      silver: 4,
      bronze: 2,
      team: 'swimmers',
    },
    {
      country: 'USA',
      continent: 'North America',
      year: 2003,
      sport: 'swim',
      gold: 10,
      silver: 4,
      bronze: 2,
      team: 'swimmers',
    },
    {
      country: 'France',
      continent: 'Europe',
      year: 2003,
      sport: 'footbal',
      gold: 1,
      silver: 4,
      bronze: 2,
      team: 'paris-team',
    },
    {
      country: 'France',
      continent: 'Europe',
      year: 2004,
      sport: 'swim',
      gold: 3,
      silver: 1,
      bronze: 1,
      team: 'paris-team',
    },
    {
      country: 'France',
      continent: 'Europe',
      year: 2005,
      sport: 'swim',
      gold: 3,
      silver: 1,
      bronze: 1,
      team: 'toulouse-team',
    },
  ]);

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

  const countReducer = {
    initialValue: 0,
    reducer: (v: number) => v + 1,
  };

  const columns = [
    {
      name: 'country',
      defaultFlex: 1,
      header: 'Country'
    },
    {
      name: 'continent',
      defaultFlex: 1,
      header: 'Continent'
    },
    {
      name: 'year',
      type: 'number',
      header: 'Year',
    },
    {
      name: 'gold',
      groupSummaryReducer: sumReducer,
      render: ({ value }) => (value || 0) + " gold",
      renderSummary: ({ value, data }) => (value || 0) + " gold medals",
      header: 'Gold medals'
    },
    {
      name: 'silver',
      groupSummaryReducer: sumReducer,
      header: 'Silver medals'
    },
    {
      name: 'bronze',
      groupSummaryReducer: sumReducer,
      header: 'Bronze medals'
    },
    {
      name: 'sport',
      header: 'Sport'
    },
  ];

const App = () => {
  const [enablePivot, setEnablePivot] = useState(true)
  const [groupBy, setGroupBy] = useState(['continent','country','year'])
  const [pivot, setPivot] = useState([])

  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, ['continent','country','year'])
  }, [groupBy])

  const updatePivot = useCallback((keys) => {
    updateArray(pivot, setPivot, keys)
  }, [pivot])

  return (
    <div>
      <div style={{ marginTop: 20}}>
        <CheckBox
          checked={enablePivot}
          onChange={setEnablePivot}
        >
          Enable pivot
        </CheckBox>
      </div>
      <div style={{ marginTop: 20}}>
        <CheckBox
          disabled={!enablePivot}
          checked={pivot.indexOf('sport') !== -1}
          onChange={checked => updatePivot({ sport: checked})}
        >
          Pivot by <b>sport</b> column values
        </CheckBox>
      </div>

      <div style={{ marginTop: 20}}>
        <CheckBox
          checked={groupBy.indexOf('continent') !== -1}
          onChange={checked => updateGroupBy({ continent: checked })}
        >
          Group by continent
        </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('year') !== -1}
          onChange={checked => updateGroupBy({ year: checked})}
        >
          Group by year
        </CheckBox>
      </div>

      <ReactDataGrid
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}

        pivot={enablePivot? pivot: null}
        groupBy={groupBy}

        groupNestingSize={40}
        onGroupByChange={setGroupBy}

        groupSummaryReducer={countReducer}
        groupColumn={{
          defaultFlex: 1,
          minWidth: 250,
          renderGroupValue: ({ value, groupSummary }) => (
            <React.Fragment>
              {value} ({groupSummary} records)
            </React.Fragment>
          ),
        }}
      />
    </div>
  );
}

export default () => <App />

IColumn | () => IColumn
default: undefined

This is useful when displaying summary columns for each pivoted column - so it's only needed when showPivotSummaryColumns=true
summaryColumn can be a a column configuration object, or a function that returns a column configuration.
The corresponding item in the pivot array also needs to contain a name - the name or the id of a column to be used for pivoting.
You also need to specify summaryReducer in order to specify how the pivot column summary will be computed.
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',
    hedaer: 'Id',
    defaultVisible: false,
    type: 'number',
    maxWidth: 100,
  },
  {
    id: 'year',
    name: 'date',
    header: 'Year',
    pivotToString: (_, { data }) => {
      return data.date.split('-')[0];
    },
  },
  {
    id: 'q1',
    header: 'Q1',
    name: 'amount',
    pivotName: 'q1',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month <= 3),
    render: ({ value }) => currency(value)
  },

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

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

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

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: {
      style: { color: '#7986cb' }
    }
  }
]

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</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={180}
        pivot={enablePivot ? pivot : null}
        groupBy={groupBy}
        showPivotSummaryColumns={showPivotSummaryColumns}
        pivotGrandSummaryColumn={{
          header: 'TOTAL',
          style: { color: '#ef9a9a' },
          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;

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

              let result;

              if (pivotSummaryPath && pivotSummaryPath.length) {

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

                result = summary[pivotValue];

              } else  if (pivotColumnPath) {

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

              } else if (pivotGrandSummaryColumn) {

                result = summary.total;

              }

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

export default () => <App />;

{reducer,initialValue,complete}
default: undefined

This is useful when displaying summary columns for each pivoted column - so it's only needed when showPivotSummaryColumns=true
The corresponding item in the pivot array also needs to contain a name, and can also contain a summaryColumn - which can be a a column configuration object, or a function that returns a column configuration.
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',
    header: 'Q1',
    name: 'amount',
    pivotName: 'q1',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month <= 3),
    render: ({ value }) => currency(value),
    textAlign: 'end',
  },

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

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

  {
    id: 'q4',
    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: {
      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])

  const updatePivot = useCallback((keys) => {
    updateArray(pivot, keys);
  }, [pivot])

  return (
    <div>
      <h3>Grid pivoted by year</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={180}
        pivot={enablePivot ? pivot : null}
        groupBy={groupBy}
        showPivotSummaryColumns={showPivotSummaryColumns}
        pivotGrandSummaryColumn={{
          header: 'TOTAL',
          style: { color: '#ef9a9a' },
          render: ({ data }) => <b>{currency(data.groupSummary.grandTotal)}</b>
        }}
        onGroupByChange={groupBy => setGroupBy(groupBy)}
        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;

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

              let result;

              if (pivotSummaryPath && pivotSummaryPath.length) {

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

                result = summary[pivotValue];

              } else  if (pivotColumnPath) {

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

              } else if (pivotGrandSummaryColumn) {

                result = summary.total;

              }

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

export default () => <App />;

IColumn
default: undefined

Configures the grand summary column - only available when showPivotSummaryColumns=true
If you only want pivot summary columns, but not a grand summary column at the end, simply don't specify the 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: 'Contry' },
  { 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',
    header: 'Q1',
    name: 'amount',
    pivotName: 'q1',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month <= 3),
    render: ({ value }) => currency(value)
  },

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

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

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

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: {
      textAlign: 'center',
      style: { color: '#7986cb' }
    }
  }
]

const App = () => {
  const [enablePivot, setEnablePivot] = useState(true)
  const [groupBy, setGroupBy] = useState(['region', 'city'])
  const [showPivotSummaryColumns, setShowPivotSummaryColumns] = useState(true)
  const [showPivotGrandSummaryColumn, setShowPivotGrandSummaryColumn] = 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</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={180}
        pivot={enablePivot ? pivot : null}
        groupBy={groupBy}
        showPivotSummaryColumns={showPivotSummaryColumns}
        pivotGrandSummaryColumn={showPivotGrandSummaryColumn? {
          header: 'TOTAL',
          style: { color: '#ef9a9a' },
          render: ({ data }) => <b>{currency(data.groupSummary.grandTotal)}</b>
        }: null}
        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;

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

              let result;

              if (pivotSummaryPath && pivotSummaryPath.length) {
                const pivotInfo = [...pivotSummaryPath].pop();
                const pivotValue = pivotInfo.value;

                result = summary[pivotValue];
              } else  if (pivotColumnPath) {
                result = summary[(pivotColumnPath || []).join('-')] || 0;
              } else if (pivotGrandSummaryColumn) {
                result = summary.total;
              }

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

export default () => <App />

Bool
default: true

Only applies when columnUserSelect=true
Controls whether native browser text selection is can be performed via mouse interaction, by holding the shift key when clicking to end/extend a selection.
When this prop is true, it calls event.preventDefault() for the mouseDown event that occurs inside <ReactDataGrid /> rows.
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 defaultSelected={}

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 [preventDefaultTextSelectionOnShiftMouseDown, setPreventDefaultTextSelectionOnShiftMouseDown] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={preventDefaultTextSelectionOnShiftMouseDown}
          onChange={setPreventDefaultTextSelectionOnShiftMouseDown}
        >
          Prevent default text selection on shift + mouseDown
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultSelected={defaultSelected}
        enableSelection
        columnUserSelect
        preventDefaultTextSelectionOnShiftMouseDown={preventDefaultTextSelectionOnShiftMouseDown}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Prevents row selection (onSelectionChange) being triggered on click on a row when the user moves the mouse before releasing it - this defaults to true in order to avoid selecting the row when in fact text selection/highlight is intended.
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 defaultSelected = {}

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 [preventRowSelectionOnClickWithMouseMove, setPreventRowSelectionOnClickWithMouseMove] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={preventRowSelectionOnClickWithMouseMove}
          onChange={setPreventRowSelectionOnClickWithMouseMove}
        >
        Prevent row selection on click with mouse move
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultSelected={defaultSelected}
        enableSelection
        columnUserSelect
        preventRowSelectionOnClickWithMouseMove={preventRowSelectionOnClickWithMouseMove}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(menuProps, { cellProps, props, grid })
default: undefined

Allows customization of the column context menu. Specify this function prop if you want to show custom menu items or a custom Menu component as the context menu for <ReactDataGrid /> column header. This function prop is called with menuProps as a first param. Either modify those props and set the desired properties on this object (like items) and return undefined, or return the <Menu /> component you want to render.
If the renderColumnContextMenu function prop returns undefined, the default Menu is rendered (beware, it has no items by default).
The second param passed to the renderColumnContextMenu function prop is an object with { cellPRops, props, grid }, where cellPRops are the props of the clicked column header, props are the computed props of the <ReactDataGrid /> and grid is a reference to the <ReactDataGrid /> instance.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

const gridStyle = { minHeight: 600 }

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 renderColumnContextMenu = useCallback((menuProps, { cellProps }) => {
    menuProps.items = menuProps.items.concat([
      {
        label: 'Custom item for "' + cellProps.name + '"',
        onClick: () => {
          inovua.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Column context menu item clicked'
          })
          menuProps.onDismiss()
        }
      },
      {
        label: 'Another custom menu item',
        onClick: () => {
          inovua.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Second custom column context menu item clicked!!!'
          })
          menuProps.onDismiss()
        }
      }
    ])
  }, [])

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

export default () => <App />

Fn(menuProps, { cellProps, props, grid })
default: undefined

Allows customization of the column filter context menu. Specify this function prop if you want to show custom menu items or a custom Menu component as the context menu for <ReactDataGrid /> column filter. This function prop is called with menuProps as a first param. Either modify those props and set the desired properties on this object (like items) and return undefined, or return the <Menu /> component you want to render.
If the renderColumnFilterContextMenu function prop returns undefined, the default Menu is rendered (beware, it has no items by default).
The second param passed to the renderColumnFilterContextMenu function prop is an object with { cellPRops, props, grid }, where cellPRops are the props of the clicked column header, props are the computed props of the <ReactDataGrid /> and grid is a reference to the <ReactDataGrid /> instance.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

const gridStyle = { minHeight: 600 }

const defaultFilterValue = [
  { name: 'name', type: 'string', value: '', operator: 'contains' },
  { name: 'country', type: 'string', value: '', operator: 'contains' },
  { name: 'city', type: 'string', value: '', operator: 'contains' },
  { name: 'age', type: 'number', value: null, operator: 'gt' }
];

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', defaultFlex: 1, header: 'Name' },
  { name: 'country', defaultFlex: 1,
    heade: '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 renderColumnFilterContextMenu = useCallback((menuProps, { cellProps }) => {
    menuProps.items = menuProps.items.concat([
      {
        label: 'Custom filter item for "' + cellProps.name + '"',
        onClick: () => {
          inovua.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Column context menu item clicked'
          })
        }
      },
      {
        label: 'Another custom filter item',
        onClick: () => {
          inovua.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Second custom column context menu item clicked!!!'
          })
        }
      }
    ])
  }, [])

  return (
    <div>
      <NotificationBoard id="first" />
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={defaultFilterValue}
        renderColumnFilterContextMenu={renderColumnFilterContextMenu}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(props): ReactNode
default: undefined

Allows the <ReactDataGrid /> to show a custom proxy on column reordering.
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'

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

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 [reorderColumns, setReorderColumns] = useState(true);

  const renderColumnReorderProxy = props => {
    return <div style={{ color: 'lightgreen' }}>{props.children}</div>;
  };

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          theme="default-dark"
          checked={reorderColumns}
          onChange={setReorderColumns}
        >
          Enable column reordering
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        reorderColumns={reorderColumns}
        columns={columns}
        dataSource={people}
        sortable={false}
        renderColumnReorderProxy={renderColumnReorderProxy}
      />
    </div>
  );
};

export default () => <App />;

Fn(rowDetailsInfo)
default: undefined

Allows rendering a details grid in order to make Master-details possible.
This function is called with an object, that has the following properties:
  • data - the data item corresponding to the current expanded row
  • rowSelected - specifies if the current row is selected
  • rowActive - specifies if the current row is active
  • rowExpanded - specifies if the current row is currently expanded
  • rowId - the value of the idProperty for the current row data object
  • toggleRowExpand - you can call this function with no arguments to collapse the current row
  • dataSource - a reference to the current dataSource array that the <ReactDataGrid /> displays
This function is similar to renderRowDetails - which you can use to render anything as a row detail.
Use rowExpandHeight to determine the height of the expanded content.
For the moment, only using one level of details is fully supported using renderDetailsGrid. Further levels are possible, but not yet fully supported - this will be released in a future minor version.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

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

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

import API_URL from './API_URL'

const accountsGridStyle = { minHeight: 800 }

const getDataSource = (entity) => {
  return ({ skip, limit, sortInfo, groupBy, filterValue }) => {
    const queryParams = [
      skip ? "skip=" + skip : null,
      limit ? "limit=" + limit : null,
      groupBy && groupBy.length ? "groupBy=" + groupBy : null,
      filterValue && filterValue.length
        ? "filterBy=" + JSON.stringify(
            filterValue.filter(v => v.active !== false).map(v => ({
              value: v.value,
              name: v.name,
              operator: v.operator,
              type: v.type
            }))
          )
        : null,
      sortInfo ? "sortInfo=" + JSON.stringify(sortInfo) : null
    ]
      .filter(value => value)
      .join('&');

    return fetch(API_URL + '/' + entity + '?' + queryParams).then(response => {
      const totalCount = response.headers.get('X-Total-Count');
      return response.json().then(data => {
        return { data, count: parseInt(totalCount) };
      })

    })
  }
}

const accountsDataSource = getDataSource('accounts')

const floatNumber = value => Number(value).toLocaleString(undefined, {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

const renderGroupTitle = value => value || 'N/A';
const renderLabeledGroupTitle = value => value ? value.label : 'N/A';
const defaultVisible = false

const GridLink = ({ value }) => <a style={{ color: '#9ba7b4' }} href={value} target="_blank">
  {value}
</a>

const columns = [
  { name: 'id', maxWidth: 50, defaultVisible, header: 'Id', defaultVisible: false },
  { name: 'name', renderGroupTitle, header: 'Name' },
  { name: 'email', renderGroupTitle, header: 'Email' },
  { name: 'phone', renderGroupTitle, header: 'Phone' },
  {
    name: 'website',
    header: 'Website',
    renderGroupTitle,
    render: ({ data }) => <GridLink value={data.website} />
  },
  {
    name: 'type',
    header: 'Type',
    renderGroupTitle,
    groupToString: value => value ? value.label: 'N/A',
    filterEditor: SelectFilter,
    sortName: 'type.label',
    groupByName: 'type.label',
    render: ({ data }) => {
      return data.type && data.type.label;
    }
  },
  {
    name: 'industry',
    header: 'Industry',
    filterEditor: SelectFilter,
    renderGroupTitle,
    groupToString: value => value ? value.label: 'N/A',
    sortName: 'industry.label',
    groupByName: 'industry.label',
    render: ({ data }) => {
      return data.industry && data.industry.label;
    }
  },
  {
    name: 'annualRevenue',
    header: 'Annual Revenue',
    filterEditor: NumberFilter,
    defaultVisible,
    renderGroupTitle,
    type: 'number',
    filterDelay: 500,
    render: ({ data }) => "$ " + floatNumber(data.annualRevenue)
  },
  {
    name: 'noOfEmployees',
    header: '# of Employees',
    filterEditor: NumberFilter,
    defaultVisible,
    renderGroupTitle
  },
  {
    name: 'facebook',
    header: 'Facebook',
    renderGroupTitle,
    defaultVisible,
    render: ({ data }) => <GridLink value={data.facebook} />
  },
  {
    name: 'twitter',
    header: 'Twitter',
    renderGroupTitle,
    defaultVisible,
    render: ({ data }) => <GridLink value={data.twitter} />
  },
  {
    name: 'linkedIn',
    header: 'LinkedIn',
    renderGroupTitle,
    defaultVisible,
    render: ({ data }) => <GridLink value={data.linkedIn} />
  }
];

const dataSourceCache = {}

const contactsColumns = [
  { name: 'id', maxWidth: 50, defaultVisible, header: 'Id', defaultVisible: false },
  {
    name: 'firstName',
    header: 'Name',
    renderGroupTitle,
    render: ({ data }) => data.firstName + " " + data.lastName
  },
  { name: "email", renderGroupTitle, header: 'Email' },
  { name: "phone", renderGroupTitle, header: 'Phone' },
  {
    name: "account",
    header: 'Account',
    defaultVisible,
    groupByName: "account.name",
    sortName: "account.name",
    filterName: "account.name",
    minWidth: 250
  },
  {
    name: 'dateOfBirth',
    header: 'Date of Birth',
    defaultVisible,
    renderGroupTitle,
    render: ({ data }) => {
      return data.dateOfBirth.toString();
    }
  },
  {
    name: 'facebook',
    header: 'Facebook',
    defaultVisible,
    resizable: true,
    renderGroupTitle,
    group: 'socialMedia',
    render: ({ data }) => {
      return <GridLink value={data.facebook} />;
    }
  },
  {
    name: 'twitter',
    header: 'Twitter',
    group: 'socialMedia',
    resizable: true,
    defaultVisible,
    renderGroupTitle,
    render: ({ data }) => {
      return <GridLink value={data.twitter} />;
    }
  },
  {
    name: 'linkedIn',
    header: 'Linked In',
    defaultVisible,
    group: 'socialMedia',
    resizable: true,
    renderGroupTitle,
    render: ({ data }) => {
      return <GridLink value={data.linkedIn} />;
    }
  },
  {
    name: 'address',
    header: 'Address',
    defaultVisible,
    renderGroupTitle,
    group: 'contactInfo'
  }
];

const getContactsFilterValue = (account) => {
  return [
    {
      name: 'account.id',
      value: account ? account.id: '',
      operator: 'eq',
      type: 'string'
    },
    {
      name: 'firstName',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'phone',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'email',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'account',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'facebook',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'twitter',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'address',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'createdBy',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'linkedIn',
      type: 'string',
      operator: 'contains',
      value: ''
    },
    {
      name: 'permissionToCall',
      type: 'bool',
      operator: 'eq',
      value: null
    },
    {
      name: 'permissionToEmail',
      type: 'bool',
      operator: 'eq',
      value: null
    }
  ]
}

const defaultGroupBy = []

const accountRowHeight = 40
const contactRowHeight = accountRowHeight
const accountExpandHeight = 500

const contactsDataSource = getDataSource('contacts')

const App = () => {
  const [accountRowHeights, setAccountRowHeights] = useState({})

  const renderContactsGrid = useCallback(({ data }) => {
    const defaultFilterValue = getContactsFilterValue(data);

    return (
      <ReactDataGrid
        defaultFilterValue={defaultFilterValue}
        dataSource={contactsDataSource}
        pagination
        columns={contactsColumns}
        columnDefaultWidth={200}
      />
    );
  }, [])

  return (
    <ReactDataGrid
      dataSource={accountsDataSource}
      style={accountsGridStyle}
      rowHeight={accountRowHeight}
      pagination
      rowExpandHeight={accountExpandHeight}
      rowHeights={accountRowHeights}
      renderDetailsGrid={renderContactsGrid}
      defaultGroupBy={defaultGroupBy}
      columnDefaultWidth={200}
      columns={columns}
    />
  );
}

export default () => <App />

Fn({ domProps: Object, size: Number, rtl: Bool })
default: undefined

Customise collapse tool for groups.
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: 400 };

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

const defaultGroupBy = ['country'];

const renderGroupCollapseTool = ({ domProps, size, rtl }) => {
  return (
    <svg {...domProps} height={size} width={size} viewBox="0 0 48 48">
      {rtl ? (
        <g transform="rotate(180, 24, 24)">
          <path d="M24 40 21.9 37.85 34.25 25.5H8V22.5H34.25L21.9 10.15L24 8L40 24Z" />
        </g>
      ) : (
        <path d="M24 40 21.9 37.85 34.25 25.5H8V22.5H34.25L21.9 10.15L24 8L40 24Z" />
      )}
    </svg>
  );
};

const renderGroupExpandTool = ({ domProps, size }) => {
  return (
    <svg {...domProps} height={size} width={size} viewBox="0 0 48 48">
      <path d="M24 40 8 24 10.1 21.9 22.5 34.3V8H25.5V34.3L37.9 21.9L40 24Z" />
    </svg>
  );
};

const App = () => {
  const [rtl, setRtl] = useState(false);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={rtl}
          onChange={setRtl}
        >
          Right-to-left
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={defaultGroupBy}
        columns={columns}
        dataSource={people}
        rtl={rtl}
        renderGroupCollapseTool={renderGroupCollapseTool}
        renderGroupExpandTool={renderGroupExpandTool}
      />
    </div>
  )
}

export default () => <App />

Fn({ domProps: Object, size: Number, rtl: Bool })
default: undefined

Customise expand tool for groups.
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: 400 };

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

const defaultGroupBy = ['country'];

const renderGroupCollapseTool = ({ domProps, size, rtl }) => {
  return (
    <svg {...domProps} height={size} width={size} viewBox="0 0 48 48">
      {rtl ? (
        <g transform="rotate(180, 24, 24)">
          <path d="M24 40 21.9 37.85 34.25 25.5H8V22.5H34.25L21.9 10.15L24 8L40 24Z" />
        </g>
      ) : (
        <path d="M24 40 21.9 37.85 34.25 25.5H8V22.5H34.25L21.9 10.15L24 8L40 24Z" />
      )}
    </svg>
  );
};

const renderGroupExpandTool = ({ domProps, size }) => {
  return (
    <svg {...domProps} height={size} width={size} viewBox="0 0 48 48">
      <path d="M24 40 8 24 10.1 21.9 22.5 34.3V8H25.5V34.3L37.9 21.9L40 24Z" />
    </svg>
  );
};

const App = () => {
  const [rtl, setRtl] = useState(false);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={rtl}
          onChange={setRtl}
        >
          Right-to-left
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={defaultGroupBy}
        columns={columns}
        dataSource={people}
        rtl={rtl}
        renderGroupCollapseTool={renderGroupCollapseTool}
        renderGroupExpandTool={renderGroupExpandTool}
      />
    </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 in grids configured with groupBy.
Also available at column-level, see column.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 renderGroupTitle = (value, { data }) => {
  const columns = data.fieldPath.map(col => col === data.name ? col.toUpperCase() : col)
  const path = columns && columns.length && columns.join('>');
  return path + ': ' + data.value
}

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}
        renderGroupTitle={renderGroupTitle}
      />
    </div>
  );
}

export default () => <App />

({visible,livePagination,zIndex,loadingText})=>ReactNode
default: undefined

Allows rendering a custom load mask.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const gridStyle = { minHeight: 550 }

const renderLoadMask = ({
  visible,
  livePagination,
  loadingText,
  zIndex
}) => {
  return <div style={{
    top: 0, left: 0, right: 0, bottom: 0,
    zIndex,
    background: 'rgba(121, 134, 203, 0.25)',
    color: '#ef9a9a',
    opacity: 0.6,
    display: 'flex',
    position: 'absolute',
    alignItems: 'center',
    justifyContent: 'center'
  }}>
    Loading...
  </div>
}

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}
        renderLoadMask={renderLoadMask}
        columns={columns}
        dataSource={[]}
      />
    </div>
  );
}

export default () => <App />

Fn(props: Object)
default: undefined

Specifies a custom render function for the context menu tool/icon.
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 renderMenuTool = ({ className }) => {
  return (
    <svg className={className} height="24px" viewBox="0 0 24 24" width="24px">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M3 18h13v-2H3v2zm0-5h10v-2H3v2zm0-7v2h13V6H3zm18 9.59L17.42 12 21 8.41 19.59 7l-5 5 5 5L21 15.59z" />
    </svg>
  );
};

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,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 }
]

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

export default () => <App />

Fn(domProps, cellProps)
default: undefined

Can be used to specify & render a custom tool for node collapse/expand/load in a <ReactDataGrid /> with the tree functionality.
Returning undefined is possible - it's a common scenario, if you just want to enhance/update the passed domProps.
The cellProps object received as a second parameter is an enhanced cellProps object, meaning it also contains information about the current tree node - it contains the following extra props:
  • leafNode - specifies if the current node is a leaf
  • nodeCollapsed - bool prop that specifies if the current node is collapsed
  • nodeLoading - bool prop that specifies if the current node is currently loading
  • nodeProps - an object with more info about the node - parentId, path, depth, etc
  • toggleNodeExpand - function which can be called if you want to update the expand/collapsed state of the node. When you call this function you don't have to pass any params to it.
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 renderNodeTool = (domProps) => {
  domProps.style.color = '#7986cb'
  domProps.style.fill = '#7986cb'
}

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"
        renderNodeTool={renderNodeTool}
        expandedNodes={expandedNodes}
        onExpandedNodesChange={onExpandedNodesChange}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        />
    </div>
  );
}

export default () => <App />

Fn(paginationProps: Object)
default: undefined

This function prop can be used to render a totally different pagination toolbar/component. The paginationProps argument contains all the necessary info & callback functions to display a pagination toolbar and respond to user interaction properly.
In fact, the <ReactDataGrid /> PaginationToolbar is an independent component, and it is rendered using the same paginationProps object.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

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

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

import DATASET_URL from './DATASET_URL'

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

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

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 dataSource = useCallback(loadData, [])

  const renderPaginationToolbar = useCallback((paginationProps) => {
    return <div style={{ height: 89 }}>
      <PaginationToolbar {...paginationProps} bordered={false} />
      <div style={{background: '#7986cb', color: '#2e3439', padding: '16px 8px' }}>
        This section is part of the customized pagination toolbar
      </div>
    </div>
  }, [])

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

export default () => <App />

Fn(menuProps, { rowProps, cellProps, computedProps, grid })
default: undefined

Specify this function prop if you want to show a custom Menu component as the context menu for <ReactDataGrid /> rows. This function prop is called with menuProps as a first param. Either modify those props and set the desired properties on this object (like items) and return undefined, or return the <Menu /> component you want to render.
If the renderRowContextMenu function prop returns undefined, the default Menu is rendered (beware, it has no items by default).
The second param passed to the renderRowContextMenu function prop is an object with { rowProps, cellProps, computedProps, computedPropsRef }, where rowProps are the props of the clicked row, cellProps are the props of the clicked cell, computedProps are the computed props of the <ReactDataGrid /> and computedPropsRef is a ref to the latest computedProps object
import React, { 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', 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 renderRowContextMenu = useCallback((menuProps, { rowProps }) => {
    menuProps.autoDismiss = true
    menuProps.items = [
      {
        label: 'Row ' + rowProps.rowIndex
      },
      {
        label: 'Want to visit ' + rowProps.data.country + '?'
      }
    ]
  }, [])

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

export default () => <App />

Fn({ data, rowSelected, rowActive, dataSource, rowIndex, toggleRowExpand })
default: undefined

This function is called when a row is expanded. It is called with an object, that has the following properties:
  • data - the data item corresponding to the current expanded row
  • rowSelected - specifies if the current row is selected
  • rowActive - specifies if the current row is active
  • rowExpanded - specifies if the current row is currently expanded
  • rowId - the value of the idProperty for the current row data object
  • toggleRowExpand - you can call this function with no arguments to collapse the current row
  • dataSource - a reference to the current dataSource array that the <ReactDataGrid /> displays
Specify rowExpandHeight to control the height of the expanded rows. As a result, the row details available height is equal to rowExpandHeight - rowHeight.
See related rowDetailsWidth.
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 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 = () => {
  return (
    <ReactDataGrid
      idProperty="id"
      defaultExpandedRows={defaultExpandedRows}
      renderRowDetails={renderRowDetails}
      style={gridStyle}
      rowExpandHeight={400}
      columns={columns}
      dataSource={people}
    />
  );
}

export default () => <App />

Fn()
default: undefined

Customise collapse icon from the row details column.
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 renderRowDetails = ({ data }) => {
  return (
    <div style={{ padding: 20 }}>
      <h3>Row details:</h3>
      <table>
        <tbody>
          {Object.keys(data).map((name, i) => {
            return (
              <tr key={i}>
                <td>{name}</td>
                <td>{data[name]}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

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

const renderRowDetailsExpandIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11H7v-2h10v2z" />
    </svg>
  );
};

const renderRowDetailsCollapsedIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" />
    </svg>
  );
};

const renderRowDetailsMoreIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
    </svg>
  );
};

const App = () => {
  return (
    <div>
      <h3>Grid showing row details on expand - controlled</h3>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
        renderRowDetailsExpandIcon={renderRowDetailsExpandIcon}
        renderRowDetailsCollapsedIcon={renderRowDetailsCollapsedIcon}
        renderRowDetailsMoreIcon={renderRowDetailsMoreIcon}
      />
    </div>
  );
};

export default () => <App />;

Fn()
default: undefined

Customise expand icon from the row details column.
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 renderRowDetails = ({ data }) => {
  return (
    <div style={{ padding: 20 }}>
      <h3>Row details:</h3>
      <table>
        <tbody>
          {Object.keys(data).map((name, i) => {
            return (
              <tr key={i}>
                <td>{name}</td>
                <td>{data[name]}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

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

const renderRowDetailsExpandIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11H7v-2h10v2z" />
    </svg>
  );
};

const renderRowDetailsCollapsedIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" />
    </svg>
  );
};

const renderRowDetailsMoreIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
    </svg>
  );
};

const App = () => {
  return (
    <div>
      <h3>Grid showing row details on expand - controlled</h3>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
        renderRowDetailsExpandIcon={renderRowDetailsExpandIcon}
        renderRowDetailsCollapsedIcon={renderRowDetailsCollapsedIcon}
        renderRowDetailsMoreIcon={renderRowDetailsMoreIcon}
      />
    </div>
  );
};

export default () => <App />;

Fn()
default: undefined

Customise more icon from the row details 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 renderRowDetails = ({ data }) => {
  return (
    <div style={{ padding: 20 }}>
      <h3>Row details:</h3>
      <table>
        <tbody>
          {Object.keys(data).map((name, i) => {
            return (
              <tr key={i}>
                <td>{name}</td>
                <td>{data[name]}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

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

const renderRowDetailsExpandIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11H7v-2h10v2z" />
    </svg>
  );
};

const renderRowDetailsCollapsedIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" />
    </svg>
  );
};

const renderRowDetailsMoreIcon = () => {
  return (
    <svg height="24px" viewBox="0 0 24 24" width="24px" fill="#fafafa">
      <path d="M0 0h24v24H0V0z" fill="none" />
      <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
    </svg>
  );
};

const App = () => {
  return (
    <div>
      <h3>Grid showing row details on expand - controlled</h3>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
        renderRowDetailsExpandIcon={renderRowDetailsExpandIcon}
        renderRowDetailsCollapsedIcon={renderRowDetailsCollapsedIcon}
        renderRowDetailsMoreIcon={renderRowDetailsMoreIcon}
      />
    </div>
  );
};

export default () => <App />;

Fn({ data, dragIndex }): ReactNode
default: undefined

Allows the <ReactDataGrid /> to show a custom proxy on row reordering.
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 renderRowReorderProxy = ({data}) => {
  return <div style={{ paddingLeft: 30 }}>ID: {data.id} - Name: {data.name}</div>
}

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

const App = () => {
  return (
    <div>
      <h3>Drag to reorder - also notice custom reorder proxy</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowHeight={40}
        rowReorderColumn
        renderRowReorderProxy={renderRowReorderProxy}
        columns={columns}
        dataSource={[].concat(people)}
      />
    </div>
  )
}

export default () => <App />

Fn(direction, extraProps)
default: undefined

Specifies a custom render function for the sort tool/icon for sortable columns. Can be overriden at column level, by columns.renderSortTool.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import Arrow from './Arrow'
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}>
    {direction === -1 ? <Arrow type="activeUp" style={arrowStyle} /> : <Arrow type="up" style={arrowStyle} />}
    {direction === 1 ? <Arrow type="activeDown" style={arrowStyle} /> : <Arrow type="down" 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 },
  { name: 'firstName', header: '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', type: 'number', defaultFlex: 1 }
]

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

export default () => <App />

Fn({ domProps: Object, size: number })
default: undefined

Customize collapse tool.
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 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', header: 'Name', defaultFlex: 1 },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const defaultExpandedNodes = { 1: true }

const App = () => {
  const [showTools, setShowTools] = useState(true);

  const renderCollapseTool = ({ domProps, size }) => {
    const style = Object.assign(domProps.style, { fill: 'red' });
    return (
      <svg
        {...domProps}
        height={size}
        viewBox="0 0 24 24"
        width={size}
        style={style}
      >
        <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
      </svg>
    );
  };

  const renderExpandTool = ({ domProps, size }) => {
    const style = Object.assign(domProps.style, { fill: 'red' });
    return (
      <svg
        {...domProps}
        height={size}
        viewBox="0 0 24 24"
        width={size}
        style={style}
      >
        <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" />
      </svg>
    );
  };

    return (
    <div>
      <h3>TreeGrid with custom collapse tool</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={showTools} onChange={setShowTools}>Show tools</CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        renderTreeCollapseTool={showTools ? renderCollapseTool : null}
        renderTreeExpandTool={showTools ? renderExpandTool : null}
        expandOnMouseDown
      />
    </div>
  );
}

export default () => <App />

Fn({ domProps: Object, size: number })
default: undefined

Customize expand tool.
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 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', header: 'Name', defaultFlex: 1 },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const defaultExpandedNodes = { 1: true }

const App = () => {
  const [showTools, setShowTools] = useState(true);

  const renderCollapseTool = ({ domProps, size }) => {
    const style = Object.assign(domProps.style, { fill: 'red' });
    return (
      <svg
        {...domProps}
        height={size}
        viewBox="0 0 24 24"
        width={size}
        style={style}
      >
        <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
      </svg>
    );
  };

  const renderExpandTool = ({ domProps, size }) => {
    const style = Object.assign(domProps.style, { fill: 'red' });
    return (
      <svg
        {...domProps}
        height={size}
        viewBox="0 0 24 24"
        width={size}
        style={style}
      >
        <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" />
      </svg>
    );
  };

    return (
    <div>
      <h3>TreeGrid with custom expand tool</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={showTools} onChange={setShowTools}>Show tools</CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        renderTreeCollapseTool={showTools ? renderCollapseTool : null}
        renderTreeExpandTool={showTools ? renderExpandTool : null}
        expandOnMouseDown
      />
    </div>
  );
}

export default () => <App />

Fn({ domProps: Object, size: number, className: string })
default: undefined

Customize loading spinner.
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 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', header: 'Name', defaultFlex: 1 },
  { name: 'size', defaultWidth: 120, header: 'Size' }
]

const defaultExpandedNodes = { 1: true }

const App = () => {
  const [showLoadingSpinner, setShowLoadingSpinner] = useState(true);

  const renderTreeLoadingTool = ({ domProps, size, className }) => {
    if (!showLoadingSpinner) {
      return (
        <div style={Object.assign(domProps.style, { width: size })}></div>
      );
    }

    return (
      <svg
        {...domProps}
        className={className}
        height={size}
        viewBox="0 0 24 24"
        width={size}
        fill="#49ffff"
      >
        <path d="M0 0h24v24H0V0z" fill="none" />
        <path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" />
      </svg>
    );
  };

  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 },
        ]);
      }, 2000);
    });
  };

    return (
    <div>
      <h3>TreeGrid with custom loading spinner</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={showLoadingSpinner} onChange={setShowLoadingSpinner}>Show loading spinner</CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        renderTreeLoadingTool={renderTreeLoadingTool}
        loadNode={loadNode}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Specifies whether column reordering is enabled or not.
Marking a column as column.draggable=false will not allow the user to drag the column and move it somewhere else. Note, however, that although a column is not draggable, it can change its position because other draggable columns can be drag-dropped and change column order.
Yet, if the first or the last column is column.draggable=false, this will ensure no other columns can be dropped over, so it will remain the first or the last column.
If you need controlled column order, use columnOrder. When the column order is changed via user interaction, onColumnOrderChange(columnOrder: String[]) is called.
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 [reorderColumns, setReorderColumns] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={reorderColumns} onChange={setReorderColumns}>
          Enable column reordering
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        reorderColumns={reorderColumns}
        columns={columns}
        dataSource={people}
        sortable={false}
      />
    </div>
  );
}

export default () => <App />

Number
default: undefined

Specifies the amount of whitespace in the grid viewport to be kept blank at the right of the last column.
This is only helpful when the <ReactDataGrid /> has flex columns.
To understand how it works, assume the following scenario: you have a grid you 3 columns: 2 fixed sized columns, 100px each, and one flex column. In this case, the flex column will occupy the 800px, as it stretches to fill the available space. In case reservedViewportWidth is specified to be 200, there will be a 200px empty space at the end, so the flex column will only be 600px wide.
Specifying null or undefined means there will be no reserved space, so the whole viewport will be used.
When a user resizes columns in a grid with flex columns (eg: makes a column smaller by 100px, and shareSpaceOnResize=false), the <ReactDataGrid /> will fire onReservedViewportWidthChange(reservedViewportWidth) (in our case, reservedViewportWidth=100)
This is a controlled prop.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultFlex: 1 },
  { name: 'firstName', header: 'Name', defaultFlex: 3 },
  { name: 'country', header: 'Country', defaultFlex: 2,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultFlex: 1 }
]

const App = () => {
  const [reservedViewportWidth, setReservedViewportWidth] = useState(null);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        Columns with flex values of 1, 2, and 3
      </div>
      <div style={{marginBottom: 20}}>
        Reserved viewport width: {reservedViewportWidth ? reservedViewportWidth + 'px' : 'none'}.
        Resize/shrink columns and then click the reset button below.
      </div>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => setReservedViewportWidth(null)}>
          Clear reserved width
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        reservedViewportWidth={reservedViewportWidth}
        onReservedViewportWidthChange={setReservedViewportWidth}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Specifies the resizable property for all <ReactDataGrid /> columns. Specify resizable=false to make all columns unresizable.
For specifying resizable=false only for one column, see column.resizable.
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: 'firstName', defaultFlex: 1, header: 'First Name' },
  { name: 'country', defaultFlex: 1, header: 'Country' },
  {
    id: 'desc',
    header: 'Description',
    defaultFlex: 2,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [resizable, setResizable] = useState(true)

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

export default () => <App />

String|HTMLElement|Boolean|Fn
default: undefined

Specifies the region/bounding box/element to which the row context menu is constrained to. By default, the <ReactDataGrid /> constrains the row 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, { 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: 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 = () => {
  const renderRowContextMenu = useCallback((menuProps, { rowProps }) => {
    menuProps.autoDismiss = true
    menuProps.items = [
      {
        label: 'Row ' + rowProps.rowIndex
      },
      {
        label: 'You clicked row ' + rowProps.rowIndex
      },
      {
        label: 'Want to visit ' + rowProps.data.country + '?'
      },
      {
        label: 'Menu for row ' + rowProps.rowIndex
      }
    ]
  }, [])

    return (
      <div>
      <p>Row context menu constrained to document.documentElement</p>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowContextMenuConstrainTo={true}
        rowContextMenuPosition={"fixed"}
        renderRowContextMenu={renderRowContextMenu}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}



export default () => <App />

String
default: undefined

Specifies the css position value to be used for the row context menu. If nothing is specified, the menu will have position: absolute.
Can be used in combination with rowContextMenuConstrainTo to make the menu constrained to a different element - in which case, you should use "fixed" positioning.
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: 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 = () => {
  const renderRowContextMenu = useCallback((menuProps, { rowProps }) => {
    menuProps.autoDismiss = true
    menuProps.items = [
      {
        label: 'Row ' + rowProps.rowIndex
      },
      {
        label: 'You clicked row ' + rowProps.rowIndex
      },
      {
        label: 'Want to visit ' + rowProps.data.country + '?'
      },
      {
        label: 'Menu for row ' + rowProps.rowIndex
      }
    ]
  }, [])

  return (
    <div>
      <p>Row context menu constrained to document.documentElement</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowContextMenuConstrainTo={true}
        rowContextMenuPosition={"fixed"}
        renderRowContextMenu={renderRowContextMenu}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: "max-viewport-width"

Controls the width of row details.
Possible values are:
  • "max-viewport-width" - the width of the row details will be maximum the width of the grid viewport width. When columns take up less space, the row details will be sized to the total width of the columns. If columns don't fit in the grid viewport and horizontal scrollbar is needed, the row details will be still constrained to the width of the grid viewport.
  • "min-viewport-width" - the width of the row details will be minimum the width of the grid viewport width. When columns take up less space, the row details will be sized to fill the grid viewport. If columns don't fit in the grid viewport and horizontal scrollbar is needed, the row details will grow with the total columns width, and will be scrolled together with the grid viewport.
  • "viewport-width" - the width of the row details will be exactly the width of the grid viewport width, no matter the size of grid columns.
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 rowDetailsWidthOptions = [
  { value: 'max-viewport-width', label: 'max-viewport-width' },
  { value: 'min-viewport-width', label: 'min-viewport-width' },
  { value: 'viewport-width', label: 'viewport-width' }
]

const gridStyle = { minHeight: 550 };

const renderRowDetails = ({ data }) => {
  return (
    <div style={{ background: '#434d65', color: '#c5cae9', 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 expandedRows = { 1: true };

const columns = [
  { name: 'id', defaultWidth: 300, header: 'Id', defaultVisible: false },
  { name: 'name', defaultWidth: 600, header: 'Name' },
  { name: 'country', defaultWidth: 600, header: 'Country' },
  { name: 'age', type: 'number', defaultWidth: 600, header: 'Age' }
]

const App = () => {
  const [rowDetailsWidth, setRowDetailsWidth] = useState('max-viewport-width');

  return (
    <div>
      <p>Select a value for rowDetailsWidth:</p>
      <RadioButtonGroup
        style={{ marginTop: 20, marginBottom: 20 }}
        radioOptions={rowDetailsWidthOptions}
        radioValue={rowDetailsWidth}
        onChange={({ checkedItemValue }) => setRowDetailsWidth(checkedItemValue)}
        orientation="horizontal"
      />
      <p>
        Resize grid columns to see the rowDetailsWidth in action
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={expandedRows}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        rowDetailsWidth={rowDetailsWidth}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />;

Object|Boolean
default: undefined

Configures the row expand column, when the grid has row expand enabled. By default, when the <ReactDataGrid /> has row expand enabled, this column is displayed.
Specifying false will hide this column.
All column configuration properties are available.
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', defaultWidth: 180, header: 'Age',
    render: ({ value, toggleRowExpand }) => <div>
      {value} - <Button onClick={() => toggleRowExpand()}>Toggle row</Button>
    </div>
  },
  { name: 'email', header: 'Email', defaultFlex: 1 }
]

const App = () => {
  const [rowExpandColumn, setRowExpandColumn] = useState(true);
  const [customRowExpandHeader, setCustomRowExpandHeader] = useState(false);

  let rowExpandCol;
  if (!rowExpandCol && customRowExpandHeader) {
    rowExpandCol = { header: 'Expand/collapse', defaultWidth: 125 }
  }

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={rowExpandColumn}
          onChange={setRowExpandColumn}
        >
          Show row expand column
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={!rowExpandColumn}
          checked={customRowExpandHeader}
          onChange={setCustomRowExpandHeader}
        >
          Custom row expand header icon
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        renderRowDetails={renderRowDetails}
        rowExpandColumn={rowExpandCol}
        style={gridStyle}
        rowExpandHeight={400}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number|Fn({ data })
default: 80

Controls the height of expanded rows in the <ReactDataGrid />.
For row expand to be meaningful, you have to specify renderRowDetails in order to render the row details on expand.
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 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 rowExpandHeights = [
  { label: 'small', value: 250 },
  { label: 'normal', value: 350 },
  { label: 'large', value: 450 }
]

const defaultExpandedRows = { 1: true }

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

const App = () => {
  const [rowExpandHeight, setRowExpandHeight] = useState(350);

  return (
    <div>
      <p>
        Select row expand height
      </p>
      <RadioButtonGroup
        radioOptions={rowExpandHeights}
        radioValue={rowExpandHeight}
        onChange={({ checkedItemValue }) => setRowExpandHeight(checkedItemValue)}
        orientation="horizontal"
        style={{ marginBottom: 20 }}
      />

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

export default () => <App />
If rowExpandHeight is a function, you can specify different heights for row details, as in example bellow.
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'

const gridStyle = { minHeight: 700 }

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

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

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

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

  const rowExpandHeight = ({ data }) => {
    if (data.id % 3 === 0) {
      return 400;
    }
    return 200;
  }

  return (
    <div>
      <h3>Grid showing row details with variable heights</h3>
      <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={rowExpandHeight}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Number
default: 40

Controls the height of <ReactDataGrid /> rows.
For specifying different fixed row heights for certain rows, please use rowHeights
In order to make the component fast with huge datasets, virtualization has been used extensively. Virtualization is used for both rows and columns.
Virtualizing the rows is possible because of the fixed row height (configured via rowHeight - defaults to 40). Column virtualization is performed when the number of columns is greater or equal to virtualizeColumnsThreshold (defaults to 15) or when virtualizeColumns=true.
Increasing the rowHeight value will improve the <ReactDataGrid /> rendering performance - since less rows fit into the visible <ReactDataGrid /> viewport and thus less rows are actually being rendered.
If you want to use natural row heights, you can use rowHeight=null. Read more about this topic at Flexible or natural row height. For small datasets you may also use the virtualized=false prop.
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: 60 }
]

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>
      <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}
      />
    </div>
  );
}

export default () => <App />

{[key: string]: number}
default: undefined

Specifies custom row heights for specific rows.
The keys in the rowHeights object represent the ids of the rows for which to use custom heights. The values are the heights those rows should have.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

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

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: 3, name: 'FinancePersonal.xls' },
        ]
      },
      { id: 2, name: 'MacRestore.gzip' },
      { id: 3, name: 'VSCode.dmg' },
      { id: 4, name: 'SublimeText.dmg' },
    ]
  }
]

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

const defaultExpandedNodes = { 1: true }

const rowHeights = {
  // the root nodes should have a different height
  '1': 100,
  '2': 100,
  '3': 100,
}

const App = () => {
  const [treeColumn, setTreeColumn] = useState('name');

  return (
    <div>
      <ReactDataGrid
        defaultExpandedNodes={defaultExpandedNodes}
        rowHeights={rowHeights}
        stickyTreeNodes
        treeColumn={"name"}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Bool|Object
default: undefined

Shows the row index column, which allows row resizing via d&d, just like in Excel & other Excel-like apps. Either specify true for the column to show with all defaults, or 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 most important configuration you can do is probably specifying rowIndexColumn.renderIndex.
maxRowIndex is taken into account when using the row index column, so rows cannot be sized bigger than that.
Double clicking the row resize handle will restore the row height to the value specified by rowHeight.
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', defaultWidth: 60, header: 'Id' },
  { 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 = () => {
  return (
    <ReactDataGrid
      idProperty="id"
      style={gridStyle}
      rowHeight={40}
      maxRowHeight={100}
      rowIndexColumn
      columns={columns}
      dataSource={people}
    />
  );
}

export default () => <App />

Fn(index: number): ReactNode
default: undefined

Specifies a custom render function to render the row index inside rowIndexColumn.
The default implementation of rowIndexColumn.renderIndex(index) is to render index+1.
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', defaultWidth: 60, header: 'Id' },
  { 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 = () => {
  return (
    <ReactDataGrid
      idProperty="id"
      style={gridStyle}
      rowHeight={40}
      maxRowHeight={100}
      rowIndexColumn={{
        header: '#',
        renderIndex: (index) => <b>{index + 10}</b>
      }}
      columns={columns}
      dataSource={people}
    />
  );
}

export default () => <App />

Object
default: undefined

Specify properties to be applied to all <ReactDataGrid /> rows. For conditional row styling, see rowStyle.
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 rowProps = {
  style: { color: '#ef9a9a' }
}

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

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

export default () => <App />

Boolean
default: false

Allows automatic scrolling on row reordering.
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: 250 }

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

const App = () => {
  return (
    <div>
      <h3>Drag the proxy up or down to the edge of the grid</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowReorderColumn
        columns={columns}
        dataSource={[].concat(people)}
        rowReorderAutoScroll
        rowReorderScrollByAmount={10}
      />
    </div>
  )
}

export default () => <App />

Number
default: 40

Sets the speed of scroll when rowReorderAutoScroll is enabled. A small value results in a greater speed and a large value results in a lower speed, because the prop sets the time interval (in miliseconds) in between the scrolling actions.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

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

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

const gridStyle = { minHeight: 250 }

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

const speedsDataSource = [
  { label: '5ms', id: 5 },
  { label: '15ms', id: 15 },
  { label: '25ms', id: 25 },
  { label: '50ms', id: 50 },
  { label: '100ms', id: 100 }
]

const App = () => {
  const [speed, setSpeed] = useState(15)

  return (
    <div>
      <h3>Drag the proxy up or down to the edge of the grid</h3>
      <div style={{ marginBottom: 20 }}>
        <ComboBox
          style={{ width: 200 }}
          collapseOnSelect
          changeValueOnNavigation
          dataSource={speedsDataSource}
          value={speed}
          onChange={setSpeed}
        />
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowReorderColumn
        columns={columns}
        dataSource={[].concat(people)}
        rowReorderAutoScroll
        rowReorderAutoScrollSpeed={speed}
        rowReorderScrollByAmount={10}
      />
    </div>
  )
}

export default () => <App />

Bool|Object
default: undefined

Shows the row reorder column, which allows row reordering via d&d, just. Either specify true for the column to show with all defaults, or 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.
When the grid is sorted, filtered, grouped or pivoted, the row reordering does not work, as it would be confusing.
When the dataSource is an array or a promise, if the grid is configured with row reordering, if no onRowReorder is specified, the rows will be reordered internally in the dataSource.
However, if the dataSource is a function, you have to specify onRowReorder({ data, dragRowIndex, insertRowIndex }) and implement the reordering logic yourself.
The most important configuration you can do is probably specifying rowReorderColumn.render.
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', defaultWidth: 60 },
  { name: 'name', header: 'Name', defaultWidth: 120 },
  { name: 'country', header: 'Country', defaultWidth: 120,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', type: 'number', defaultWidth: 120 }
]

const App = () => {
  return (
    <div>
      <h3>Drag to reorder</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowHeight={40}
        rowReorderColumn
        columns={columns}
        dataSource={[].concat(people)}
      />
    </div>
  )
}

export default () => <App />

Bool
default: false

Specifies if the <ReactDataGrid /> should use right-to-left direction.
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: 350 }

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

const App = () => {
  const [rtl, setRtl] = useState(false)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={rtl}
          onChange={setRtl}
        >
          Enable RTL
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        rtl={rtl}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

An object that configures the default scrolling behavior & appearance of the <ReactDataGrid />.
The scrollProps object supports many properties, but here is a short list of the most important ones:
  • autoHide - whether to hide the scrollbars while not scrolling. Defaults to true.
  • alwaysShowTrack - whether to show the scroll track all the time or only when the mouse is over it. Defaults to false, so it will only be displayed on mouseover.
  • scrollThumbWidth - the width of the scrollthumb. Defaults to 7.
  • scrollThumbStyle - a style object for the scroll thumb.
  • scrollThumbRadius - the radius of the scroll thumb. Defaults to the value of scrollThumbWidth.
Does not apply when nativeScroll=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 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 />

Bool
default: false

Specifies whether the scrollthumb track should be always visible or not. By default the scroll track is not displayed unless the user places the mouse over the scrollbar.
Does not apply when nativeScroll=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 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 />

Bool
default: true

Specifies whether the scrollbars of the <ReactDataGrid /> should hide when no scrolling is in progress. Defaults to true.
Does not apply when nativeScroll=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 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 />

Number
default: 7

Specifies the radius of the scrollbar. Defaults to the value of scrollProps.scrollThumbWidth.
Does not apply when nativeScroll=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 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 />

Object
default: undefined

Specifies a custom style object for the scrollbar.
Does not apply when nativeScroll=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 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 />

Number
default: 7

Specifies the width of the scrollbar.
Does not apply when nativeScroll=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 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 />

Number | String
default: undefined

If scrollThreshold is specified, the next page will be loaded when the user reaches the scroll max height minus scrollThreshold of the page - if the threshold is specified as a string, in pixels (for example, scrollThreshold="150px"). If scrollThreshold is a number or it is a percentage (for example, scrollThreshold="60%" or scrollThreshold=0.6), the next page will be loaded when the user reaches the specified percentage of the scroll max height.

Bool
default: true

If this is true, the scrollTop is set to 0 when filtering.
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: 250 }

const defaultFilterValue = [
  {
    name: 'firstName', value: '', operator: 'contains', type: 'string'
  }
]

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,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [scrollTopOnFilter, setScrollTopOnFilter] = useState(true)

  return (
    <div>
      <div>
        <CheckBox
          checked={scrollTopOnFilter}
          onChange={setScrollTopOnFilter}
        >
          Scroll top on filter
        </CheckBox>
        <p>Try filtering by "i" on name column</p>
      </div>
      <ReactDataGrid
        idProperty="id"
        defaultFilterValue={defaultFilterValue}
        scrollTopOnFilter={scrollTopOnFilter}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

If this is true, the scrollTop is set to 0 when grouping a column.
This is still experimental, setting this to false might not work.

Bool|'always'
default: true

By default scrollTopOnSort works with remote data and the type it is a boolean, which if it is true, the scrollTop is set to 0 when sorting. But if you want the same effect with local data, specify it to 'always'.
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: 350 }

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,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [scrollTopOnSort, setScrollTopOnSort] = useState(true)

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

export default () => <App />

String|Number|Object|Boolean
default: undefined

Specifies the selected row (or rows) in the <ReactDataGrid />. This is a controlled prop. For the uncontrolled version, see defaultSelected.
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.
When a remote dataSource is configured, you might need to use unselected (or the uncontrolled defaultUnselected) together with selected.
Specifying selected=true will render all rows as selected (even rows on other pages). At this point, you can use unselected to specify exceptions (rows that will not be rendered as unselected).
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 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({ 1: true, 2: true });

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

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

export default () => <App />

Bool
default: true

Enables multiple cell selection via the cell mousedown + drag + mouseup gesture. This is useful when multiple cellSelection is enabled.
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 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 [selectOnDrag, setSelectOnDrag] = useState(false)
  const [cellSelection, setCellSelection] = useState(defaultCellSelection)

  return (
    <div>
      <p>When selectOnDrag is enabled you can hold the mouse down on a cell and drag to another cell to create multiple cell selection.</p>
      <p>selectOnDrag: {selectOnDrag}</p>
      <div>
        <CheckBox checked={selectOnDrag} onChange={setSelectOnDrag}>
          Enable select on drag
        </CheckBox>
      </div>
      <p>
        Selected cells: {Object.keys(cellSelection).length == 0 ? 'none' : JSON.stringify(cellSelection)}.
      </p>
      <ReactDataGrid
        idProperty="id"
        selectOnDrag={selectOnDrag}
        defaultCellSelection={defaultCellSelection}
        onCellSelectionChange={setCellSelection}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

If this is true, when columns are resized, sibling/adjacent columns will share their resize space. If false, any resize that increases column width will push the next columns to the right.
When the <ReactDataGrid /> has flexible columns, and shareSpaceOnResize=false, when a column is resized (eg: made smaller), the flexible columns keep their current size and don't grow to fill the newly available space. However, they do keep their proportional size to all other flexible columns. Also, when the <ReactDataGrid /> has more available space (i.e., is resized), they do resize to keep the same empty space in the <ReactDataGrid />.
When the <ReactDataGrid /> is configured with shareSpaceOnResize=true, and a column is resized, flexible columns are resized to fill all available space to ensure that columns always fill the grid viewport horizontally.
This prop should be considered as a hint to the <ReactDataGrid /> and not as a mandatory behaviour - since there are cases when sharing space is not desirable/possible (eg - a resizable column adjacent to a non-resizable column).
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 [shareSpaceOnResize, setShareSpaceOnResize] = useState(false);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={shareSpaceOnResize} onChange={setShareSpaceOnResize}>
          Share space on resize
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        shareSpaceOnResize={shareSpaceOnResize}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

If true, row details will be rendered in the DOM even for rows which are not expanded - but will be rendered with display: none.
You can customize the styling of the row details wrapper element using rowDetailsStyle.

Bool
default: true

Controls whether the active row indicator should be displayed or not. Default to 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 people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const columns =  [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 60, 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', defaultFlex: 1, type: 'number' }
];

const App = () => {
  const [enableSelection, setEnableSelection] = useState(true);
  const [showActiveRowIndicator, setShowActiveRowIndicator] = useState(true);

  return (
    <div>
      <h3>DataGrid with active row indicator</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableSelection}
          onChange={setEnableSelection}>
            Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showActiveRowIndicator}
          onChange={setShowActiveRowIndicator}>
            Enable active row indicator
        </CheckBox>
      </div>

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

export default () => <App />

Bool
default: true

Controls whether the menus of each column displays the show/hide filtering row items.
This can be overridden by columns.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 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 [showColumnMenuFilterOptions, setShowColumnMenuFilterOptions] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showColumnMenuFilterOptions}
          onChange={setShowColumnMenuFilterOptions}
        >
          Show menu item for showing/hiding filtering row in column menu
        </CheckBox>
      </div>

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

export default () => <App />

Bool
default: true

Controls whether the menus of each column displays the group/ungroup menu items.
This can be overridden by columns.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 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 [showColumnMenuGroupOptions, setShowColumnMenuGroupOptions] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showColumnMenuGroupOptions}
          onChange={setShowColumnMenuGroupOptions}
        >
          Show column group/ungroup option in column menu
        </CheckBox>
      </div>

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

export default () => <App />

Bool
default: true

Controls whether the menus of each column displays the lock/unlock items.
This can be overridden by columns.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 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 [showColumnMenuLockOptions, setShowColumnMenuLockOptions] = useState(true);

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

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

export default () => <App />

Bool
default: true

Controls whether the menus of each column displays the sort asc/desc/unsort menu items.
This can be overridden by columns.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 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 [showColumnMenuSortOptions, setShowColumnMenuSortOptions] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showColumnMenuSortOptions}
          onChange={setShowColumnMenuSortOptions}
        >
          Show column sort/unsort option in column menu
        </CheckBox>
      </div>

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

export default () => <App />

Bool
default: true

Controls whether the column headers have the menu integration enabled or not. Defaults to true.
This can be overridden by columns.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 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 [showColumnMenuTool, setShowColumnMenuTool] = useState(true);

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

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        showColumnMenuTool={showColumnMenuTool}
        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 can be overridden by columns.showColumnMenuToolOnHover, 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 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 [showColumnMenuToolOnHover, setShowColumnMenuToolOnHover] = useState(true);

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

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

export default () => <App />

Boolean|String
default: undefined

Control the position of the group summary row - only valid when there is grouping. And only useful when you have a groupSummaryReducer.
Valid values are true, false,"start" or "end". true is the same as specifying "end"
When groupColumn is used, the group summary row is not displayed.
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 [showGroupColumn, setShowGroupColumn] = useState(false);
  const [showGroupSummaryRow, setShowGroupSummaryRow] = useState(true);
  const [groupSummaryRowPosition, setGroupSummaryRowPosition] = useState('end');

  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={showGroupColumn}
          onChange={showGroupColumn => {
            if (showGroupColumn) {
              setShowGroupSummaryRow(false);
              setGroupSummaryRowPosition('end');
            }
            setShowGroupColumn(showGroupColumn);
          }}
        >
          Use dedicated group column
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={!!showGroupSummaryRow}
          onChange={showGroupSummaryRow => {
            if (showGroupSummaryRow) {
              setShowGroupColumn(false);
            }
            setShowGroupSummaryRow(showGroupSummaryRow);
          }}
        >
          Show group summary row
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={!showGroupSummaryRow}
          checked={groupSummaryRowPosition === 'start' && showGroupSummaryRow}
          onChange={groupSummaryRowPosition => {
            const newState = groupSummaryRowPosition ? 'start' : 'end';
            setGroupSummaryRowPosition(newState);
          }}
        >
          Group summary row position - START
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        groupColumn={showGroupColumn}
        showGroupSummaryRow={showGroupSummaryRow ? groupSummaryRowPosition : false}
        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 />;

Bool
default: true

Controls header visibility. Specify showHeader=false to hide <ReactDataGrid /> headers.
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: 'city', defaultFlex: 1, header: 'City' },
  { name: 'age', type: 'number', defaultFlex: 1, header: 'Age' }
]

const App = () => {
  const [showHeader, setShowHeader] = useState(true);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={showHeader}
          onChange={setShowHeader}
        >
          Show header
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        columns={columns}
        dataSource={people}
        showHeader={showHeader}
      />
    </div>
  );
}
export default () => <App />

bool
default: true

When showPivotSummaryColumns=true, the pivoted grid will show pivot summary columns for each pivot item that specifies a pivot.summaryReducer.
The corresponding item in the pivot array also needs to contain a name, and can also contain a summaryColumn - which can be a a column configuration object, or a function that returns a column configuration.
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',
    header: 'Q1',
    name: 'amount',
    pivotName: 'q1',
    type: 'number',
    groupSummaryReducer: quarterSumReducer(month => month <= 3),
    render: ({ value }) => currency(value)
  },

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

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

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

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: {
      style: { color: '#7986cb' }
    }
  }
]

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</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={180}
        pivot={enablePivot ? pivot : null}
        groupBy={groupBy}
        showPivotSummaryColumns={showPivotSummaryColumns}
        pivotGrandSummaryColumn={{
          header: 'TOTAL',
          style: { color: '#ef9a9a' },
          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;

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

              let result;

              if (pivotSummaryPath && pivotSummaryPath.length) {

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

                result = summary[pivotValue];

              } else  if (pivotColumnPath) {

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

              } else if (pivotGrandSummaryColumn) {

                result = summary.total;

              }

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

Number
default: undefined

The controlled skip value for the <ReactDataGrid />, when pagination is enabled.
This is a controlled prop. For the uncontrolled version, see defaultSkip.
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 Button from '@inovua/reactdatagrid-community/packages/Button'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 400, 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 [skip, setSkip] = useState(10);
  const [loading, setLoading] = useState(false);

  const dataSource = useCallback(loadData, [])

  const updateSkip = useCallback((amount) => {
    return () => {
      const newSkip = skip + amount
      setSkip(Math.max(0, Math.min(newSkip, 100)))
    }
  }, [skip])

  const disabled = loading || Array.isArray(dataSource)

  return (
    <div>
      <p>Current skip: {skip}.</p>
      <div style={{ marginBottom: 20 }}>
        <Button style={{ marginRight: 8 }} onClick={updateSkip(10)} disabled={disabled}>skip += 10</Button>
        <Button onClick={updateSkip(-10)} disabled={disabled || skip == 0}>skip -= 10</Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination
        defaultLimit={10}
        skip={skip}
        onSkipChange={setSkip}
        loading={loading}
        onLoadingChange={setLoading}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

When the column auto size is enabled, by default the header width is included in computation of column resize, but if you want to skip the header and include only the column width, set skipHeaderOnAutoSize to true.
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';
import Button from '@inovua/reactdatagrid-community/packages/Button';
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox';

const gridStyle = { minHeight: 550 };

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

const App = () => {
  const [gridRef, setGridRef] = useState(null);
  const [enableColumnAutosize, setEnableColumnAutosize] = useState(true);
  const [skipHeaderOnAutoSize, setSkipHeaderOnAutoSize] = useState(false);

  const setColumnsSizesAuto = useCallback(
    () => {
      if (gridRef.current.setColumnsSizesAuto) {
        gridRef.current.setColumnsSizesAuto();
      }
    },
    [gridRef]
  );

  return (
    <div>
      <h3>Grid with colums autosize</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={enableColumnAutosize} onChange={setEnableColumnAutosize}>
          Enable column autosize
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={skipHeaderOnAutoSize} onChange={setSkipHeaderOnAutoSize}>
          Skip header on auto size
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => setColumnsSizesAuto()}>
          Set column sizes auto
        </Button>
      </div>

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

export default () => <App />;

Bool
default: true

Specifies whether sorting is enabled in the <ReactDataGrid />.
By default, columns do not specify any sorting behavior - so they "inherit" the sortable prop specified on the <ReactDataGrid />. If however they specify a custom column.sortable value, it will be honoured, even if the <ReactDataGrid /> specifies a different value for sortable prop .
For details on how remote sorting works, see Remote sorting.
For guidance on single vs multiple sorting and the usage of allowUnsort, see Single and multiple sorting.
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: 'First Name', defaultFlex: 1 },
  { name: 'age', header: 'Age', type: 'number', defaultWidth: 100 },
  {
    id: 'desc',
    header: 'Description, not sortable',
    sortable: false,
    minWidth: 100,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country,
    flex: 2
  }
]

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

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

export default () => <App />
When column contents are not text, make sure you specify a column.type to ensure proper sorting. For now, supported values are "string" and "number". Or you can specify a custom column.sort function (it should always sort records in ascending order) to accomplish custom local sorting.

Object|Object[]
default: undefined

Specifies the sort order for the <ReactDataGrid />. This is a controlled prop. For the uncontrolled version, see defaultSortInfo. The sortInfo object should contain at least two properties: name (which should be the column identifier) and dir (valid values are 1 or -1).
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.
When using controlled sorting, make sure you update the value of the sortInfo prop when onSortInfoChange(sortInfo) is called.
For rendering a custom sort tool/icon, see columns.renderSortTool.
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: 300 }

const getComparer = (sortInfo) => {
  const key = sortInfo.name;
  const direction = sortInfo.dir;
  return (a, b) => {
    if (a === b) return 0;
    return b[key] > a[key] ? -direction : direction;
  }
}

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: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', type: 'number', defaultFlex: 1 }
]

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

const initialData = [].concat(people).sort(getComparer(defaultSortInfo))

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

  const onSortInfoChange = useCallback(sortInfo => {
    const newData = !sortInfo?[].concat(people):[].concat(people).sort(getComparer(sortInfo))

    setSortInfo(sortInfo)
    setDataSource(newData)
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        Current sort info: {sortInfo ? <code>{JSON.stringify(sortInfo, null, 2)}</code>: 'none'}.
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        sortInfo={sortInfo}
        columns={columns}
        dataSource={dataSource}
        onSortInfoChange={onSortInfoChange}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Specifies whether to use sticky group rows. 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: 400 }

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

const App = () => {
  const [defaultGroupBy, setDefaultGroupBy] = useState(['country','city']);
  const [stickyGroupRows, setStickyGroupRows] = useState(false);

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={stickyGroupRows}
          onChange={setStickyGroupRows}
        >
          Use sticky group rows
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        stickyGroupRows={stickyGroupRows}
        defaultGroupBy={defaultGroupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Specifies whether the header is positioned sticky. Default 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'

const columns = [
  { name: 'name', header: 'Name', minWidth: 50, defaultFlex: 2 },
  { name: 'age', header: 'Age', maxWidth: 1000, defaultFlex: 1 }
]

const gridStyle = { minHeight: 2500 }

const dataSource = [
  { id: 1, name: 'John McQueen', age: 35 },
  { id: 2, name: 'Mary Stones', age: 25 },
  { id: 3, name: 'Robert Fil', age: 27 },
  { id: 4, name: 'Roger Robson', age: 81 },
  { id: 5, name: 'Billary Konwik', age: 18 },
  { id: 6, name: 'Bob Martin', age: 18 },
  { id: 7, name: 'Matthew Richardson', age: 54 },
  { id: 8, name: 'Ritchie Peterson', age: 54 },
  { id: 9, name: 'Bryan Martin', age: 40 },
  { id: 10, name: 'Mark Martin', age: 44 },
  { id: 11, name: 'Michelle Sebastian', age: 24 },
  { id: 12, name: 'Michelle Sullivan', age: 61 },
  { id: 13, name: 'Jordan Bike', age: 16 },
  { id: 14, name: 'Nelson Ford', age: 34 },
  { id: 15, name: 'Tim Cheap', age: 3 },
  { id: 16, name: 'Robert Carlson', age: 31 },
  { id: 17, name: 'Johny Perterson', age: 40 }
];

const App = () => {
  const [stickyHeader, setStickyHeader] = useState(true);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={stickyHeader} onChange={setStickyHeader}>Sticky header</CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        columns={columns}
        dataSource={dataSource}
        style={gridStyle}
        stickyHeader={stickyHeader}
      />
    </div>
  )
}

export default () => <App />

Bool
default: false

Specifies whether to use sticky tree nodes when in tree grids (when treeColumn is used). 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'

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', header: 'Name', defaultFlex: 1 },
  { name: 'size', header: 'Size', defaultWidth: 160 }
];

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 nestingSizes = [
  { label: '10px', id: 10},
  { label: '15px', id: 15},
  { label: '22px', id: 22},
  { label: '25px', id: 25},
  { label: '50px', id: 50}
]

const defaultExpandedNodes = { 1: true }

const App = () => {
  const [stickyTreeNodes, setStickyTreeNodes] = useState(false);

  return (
    <div>
      <h3>TreeGrid with sticky tree nodes</h3>

      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={stickyTreeNodes}
          onChange={setStickyTreeNodes}
        >
          Use sticky tree nodes (expand nodes to have vertical scrollbar)
        </CheckBox>
      </div>
      <ReactDataGrid
        treeColumn="name"
        loadNode={loadNode}
        stickyTreeNodes={stickyTreeNodes}
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

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

Specifies a summary reducer object which determines how to compute the grid-level summary to be displayed in the footer.
By using the footer summary reducer, you have the flexibility of computing all kind of summaries based on the available data.
We introduced the concept of summaryReducer - which are simple objects with the following props:
  • initialValue - the initial value to be used for the summary computation - generally a number/string/etc
  • reducer(accumulator, currentItem) - the reducer function - basically computes the summary from the accumulated value (at first call, this will equal the initialValue) and the current 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
In the snippet below, we display min, max and average values for the population column.
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>
        <div>Min: {summary.min}</div>
        <div>Max: {summary.max}</div>
        <div>Average: {summary.avg}</div>
      </div>
    }
  }
]

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

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

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>Multiple footer summaries for the population 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

Applies for grids with single (multiSelect=false) cell selection. If true (which is the default), clicking the selected cell will deselect it. If false, clicking the selected cell would not unselect it - to unselect the user has to crtl+click the cell.
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 defaultCellSelection = {"2,name": 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 [toggleCellSelectOnClick, setToggleCellSelectOnClick] = useState(true);

  return (
    <div>
      <div>
        <CheckBox
          checked={toggleCellSelectOnClick}
          onChange={setToggleCellSelectOnClick}
        >
          Toggle cell select on click
        </CheckBox>
      </div>
      <p>
        When clicking a cell it becomes both the active cell & the selected cell. Make sure you notice the difference in styling when both are applied.
      </p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        multiSelect={false}
        toggleCellSelectOnClick={toggleCellSelectOnClick}
        defaultCellSelection={defaultCellSelection}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Applies for grids with single row selection. If true, clicking the selected row will deselect it. If false (which is the default), clicking the selected row would not unselect it - to unselect the user has to crtl+click the row.
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: '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(1);
  const [toggleRowSelectOnClick, setToggleRowSelectOnClick] = useState(true);

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

  return (
    <div>
      <div>
        <CheckBox
          checked={toggleRowSelectOnClick}
          onChange={setToggleRowSelectOnClick}
        >
          Toggle row select on click
        </CheckBox>
      </div>
      <p>Selected row id: {selected}</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        toggleRowSelectOnClick={toggleRowSelectOnClick}
        defaultSelected={1}
        onSelectionChange={onSelectionChange}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

Specifies which column should have the node collapse/expand tool.
When this prop is specified, it enables the tree functionality - see the TreeGrid page to understand how the items in the dataSource can be configured to have child nodes.
Using the tree functionality in the <ReactDataGrid /> is not compatible with grouping rows.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

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

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 = { 1: true }

const comboDataSource = columns.map(c=> {
  return {
    id: c.name,
    label: c.name
  }
})

const App = () => {
  const [treeColumn, setTreeColumn] = useState('name');

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <p>Please select the treeColumn</p>
        <ComboBox
          style={{ width: 150}}
          collapseOnSelect
          clearIcon={false}
          searchable={false}
          changeValueOnNavigation
          dataSource={comboDataSource}
          value={treeColumn}
          onChange={setTreeColumn}
        />
      </div>
      <ReactDataGrid
        defaultExpandedNodes={defaultExpandedNodes}
        treeColumn={treeColumn}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Controls whether children will be deselected with the deselection of the parent.
import React, { useState, useCallback } from 'react'

import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
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: 160 }
];

const expandedNodes = { 1: true, 3: true, '3/1': true };

const App = () => {
  const [
    treeGridChildrenSelectionEnabled,
    setTreeGridChildrenSelectionEnabled,
  ] = useState(true);
  const [
    treeGridChildrenDeselectionEnabled,
    setTreeGridChildrenDeselectionEnabled,
  ] = useState(true);

  return (
    <div>
      <h3>TreeGrid with children deselection enabled</h3>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={treeGridChildrenSelectionEnabled}
          onChange={setTreeGridChildrenSelectionEnabled}
        >
          Children selection enabled
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={treeGridChildrenDeselectionEnabled}
          onChange={setTreeGridChildrenDeselectionEnabled}
        >
        Children deselection enabled
        </CheckBox>
      </div>

      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={expandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        checkboxColumn
        treeGridChildrenSelectionEnabled={treeGridChildrenSelectionEnabled}
        treeGridChildrenDeselectionEnabled={treeGridChildrenDeselectionEnabled}
      />
    </div>
  );
}

export default () => <App />

Bool
default: undefined

Controls whether children will be selected with the selection of the parent.
import React, { useState, useCallback } from 'react'

import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
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: 160 }
];

const expandedNodes = { 1: true, 3: true, '3/1': true };

const App = () => {
  const [
    treeGridChildrenSelectionEnabled,
    setTreeGridChildrenSelectionEnabled,
  ] = useState(true);

  return (
    <div>
      <h3>TreeGrid with children selection enabled</h3>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={treeGridChildrenSelectionEnabled}
          onChange={setTreeGridChildrenSelectionEnabled}
        >
          treeGridChildrenSelectionEnabled
        </CheckBox>
      </div>
      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={expandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        checkboxColumn
        treeGridChildrenSelectionEnabled={treeGridChildrenSelectionEnabled}
      />
    </div>
  );
}

export default () => <App />

Number
default: 22

Configures the size of the nesting nodes have in the tree.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

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

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', header: 'Name', defaultFlex: 1 },
  { 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 nestingSizes = [
  { label: '10px', id: 10},
  { label: '15px', id: 15},
  { label: '22px', id: 22},
  { label: '25px', id: 25},
  { label: '50px', id: 50}
]

const defaultExpandedNodes = { 1: true }

const App = () => {
  const [treeNestingSize, setTreeNestingSize] = useState(22)

    return (
    <div>
      <h3>TreeGrid with treeNestingSize configuration</h3>
      <div style={{ marginBottom: 20 }}>
        <p>Please select the tree nesting size
        </p>
        <ComboBox
          style={{ width: 150}}
          collapseOnSelect
          clearIcon={false}
          searchable={false}
          changeValueOnNavigation
          dataSource={nestingSizes}
          value={treeNestingSize}
          onChange={setTreeNestingSize}
        />
      </div>
      <ReactDataGrid
        treeColumn="name"
        loadNode={loadNode}
        defaultExpandedNodes={defaultExpandedNodes}
        treeNestingSize={treeNestingSize}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

An object that specifies which rows should not be expandable - the keys in this object should be the ids of the unexpandable rows.
For a more flexible alternative, see isRowExpandable.
When unexpandableRows prop is specified, isRowExpandable is no longer called.
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 unexpandableRows = { 1: true, 2: true }

const App = () => {
  return (
    <div>
      <p>Rows with the ids 1 and 3 are not expandable.</p>

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

export default () => <App />

Object
default: undefined

Used in combination with remote dataSource and selected.
Specifies which <ReactDataGrid /> rows should be rendered as unselected. When selected=true, all items but those specified by this prop should be selected.
The unselected object should be keyed using item ids, as specified by their idProperty.
This is a controlled prop. For the uncontrolled version, see defaultSelected. When the user selects/deselects new rows, onSelectionChange({ selected, unselected }) is called, and you need to make sure you update the value of the unselected prop to reflect the selection changes.
Most often, this is also used in combination with checkboxColumn=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 [unselected, setUnselected] = useState({ 1: true, 3: true });
  const [selected, setSelected] = useState(true);
  const [checkboxOnlyRowSelect, setCheckboxOnlyRowSelect] = useState(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 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
        columns={columns}
        checkboxOnlyRowSelect={checkboxOnlyRowSelect}
        pagination
        selected={selected}
        unselected={unselected}
        onSelectionChange={onSelectionChange}
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

The menu can update its position to the nearest menu tool when removing or adding columns.
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,
    defaultWidth: 60,
    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', defaultFlex: 1, type: 'number' },
];

const App = () => {
  const [
    updateMenuPositionOnColumnsChange,
    setUpdateMenuPositionOnColumnsChange,
  ] = useState(true);

  return (
    <div>
      <h3>Grid with update menu position when columns change</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          theme="default-dark"
          checked={updateMenuPositionOnColumnsChange}
          onChange={setUpdateMenuPositionOnColumnsChange}
        >
          updateMenuPositionOnColumnsChange
        </CheckBox>
      </div>

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

export default () => <App />;

Bool
default: "true"

If set to true, will make lockedRows have the same height as normal grid rows.
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 />

{ width: Number, height: Number }
default: undefined

By default, the <ReactDataGrid /> is reading the available viewport size from the DOM after the initial layout and in some cases, if you try to test with jsdom, for example, that doesn't happened. So, viewportSize prop it sets an initial viewport size for the grid.

Bool
default: undefined

Controls whether column virtualization is performed. By default, this prop is undefined, so column virtualization happens only when you have a number of columns equal or greater than virtualizeColumnsThreshold (which defaults to 15).
When virtualizeColumns is specified, column virtualization is applied depending on its value.
Besides being able to render a huge number of rows, the <ReactDataGrid /> is also built to support a big number of columns. Although most grids people use have 10 columns or less, the<ReactDataGrid /> should be able to handle 50 columns quite easily.
All this is possible when column virtualization is enabled
Rendering & fitting a smaller number of columns in the viewport means the <ReactDataGrid /> is snappier. So a performance tip when column virtualization is enabled would be to increase the column widths so less columns can be visible at a single moment in the viewport.
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: 550, marginTop: 10 }

const empty = () => null

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultWidth: 135, header: 'First Name' },
  { name: 'lastName', defaultWidth: 135, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultWidth: 135, header: 'Email' },
  { id: 'col_4', header: 'Column 4', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_5', header: 'Column 5', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_6', header: 'Column 6', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_7', header: 'Column 7', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_8', header: 'Column 8', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_9', header: 'Column 9', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_10', header: 'Column 10', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_11', header: 'Column 11', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_12', header: 'Column 12', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_13', header: 'Column 13', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_14', header: 'Column 14', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_15', header: 'Column 15', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_16', header: 'Column 16', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_17', header: 'Column 17', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_18', header: 'Column 18', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_19', header: 'Column 19', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_20', header: 'Column 20', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_21', header: 'Column 21', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_22', header: 'Column 22', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_23', header: 'Column 23', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_24', header: 'Column 24', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_25', header: 'Column 25', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_26', header: 'Column 26', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_27', header: 'Column 27', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_28', header: 'Column 28', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_29', header: 'Column 29', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) },
  { id: 'col_30', header: 'Column 30', minWidth: 135, render: ({ data, rowIndex, columnIndex }) => 'Row ' + rowIndex + ', col ' + (columnIndex + 1) }
]

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 [virtualizeColumns, setVirtualizeColumns] = useState(true);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={virtualizeColumns}
          onChange={setVirtualizeColumns}
        >Virtualize columns</CheckBox>
      </div>
      <ReactDataGrid
        key={'grid-' + virtualizeColumns}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        rowHeight={50}
        dataSource={dataSource}
        limit={800}
        virtualizeColumns={virtualizeColumns}
      />
    </div>
  );
}

export default () => <App />

Number
default: 15

When virtualizeColumns is undefined, column virtualization is applied when the number of columns is greater or equal to the value of virtualizeColumnsThreshold.
See virtualizeColumns for performance considerations and recommendations.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import DATASET_URL from './DATASET_URL'

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

const empty = () => null

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', maxWidth: 40 },
  { name: 'firstName', defaultWidth: 135, header: 'First Name' },
  { name: 'lastName', defaultWidth: 135, header: 'Last Name' },
  { name: 'email', groupBy: false, defaultWidth: 135, header: 'Email' },
  { id: 'col_5', header: 'Column 5', defaultWidth: 135, render: ({ data, rowIndex }) => 'dummy col1' },
  { id: 'col_6', header: 'Column 6', defaultWidth: 135, render: ({ data, rowIndex }) => 'dummy col2' },
  { id: 'col_7', header: 'Column 7', defaultWidth: 135, render: ({ data, rowIndex }) => 'dummy col3' },
  { id: 'col_8', header: 'Column 8', defaultWidth: 135, render: ({ data, rowIndex }) => 'dummy col4' },
  { id: 'col_9', header: 'Column 9', defaultWidth: 135, render: ({ data, rowIndex }) => 'dummy col5' },
  { id: 'col_10', header: 'Column 10', defaultWidth: 135, render: ({ data, rowIndex }) => 'dummy col6' }
]

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 dataSource = useCallback(loadData, [])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        virtualizeColumnsThreshold={10}
        style={gridStyle}
        columns={columns}
        rowHeight={50}
        dataSource={dataSource}
        limit={800}
      />
    </div>
  );
}

export default () => <App />

Bool
default: true

Controls virtualization for the <ReactDataGrid /> rows. When set to false, the <ReactDataGrid /> renders all the rows in the dataSource to the DOM without any optimization.
Beware, configuring virtualized=false will in most cases lead to performance issues! It's only feasible (performance-wise) to use this when you are sure your dataset is small, as when no virtualization is applied all grid records end up being rendered into the DOM.
A scenario when you might have to avoid virtualization is when the rows have flexible or natural height (<ReactDataGrid /> components configured with rowHeight=null) where the contents of <ReactDataGrid /> cells make the rows have different heights and there is no fixed rowHeight.
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: 500, marginTop: 10 }

const emulateRowRenderComputations = () => {
  for (let i = 0; i < 1000; i++) {
    const array = new Array(i)
  }
}

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' },
  {
    name: 'permissionToCall', minWidth: 200,
    header: 'Permission to call',
    render: ({data}) => {
      emulateRowRenderComputations()
      return data.permissionToCall ? 'Yes' : 'No'
    },
    renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
  }
]

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 [virtualized, setVirtualized] = useState(false);

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <CheckBox
        style={{ marginBottom: 20 }}
        checked={virtualized}
        onChange={setVirtualized}
      >
        virtualized
      </CheckBox>
      <ReactDataGrid
        key={virtualized}
        sortable={false}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        pagination
        pageSizes={[100, 400, 800]}
        dataSource={dataSource}
        defaultLimit={200}
        virtualized={virtualized}
      />
    </div>
  );
}

export default () => <App />

Callback props

Fn(filterRows: Number)
default: undefined

Called after every filtering and returns the number of remaining rows.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

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

const App = () => {
  const [filterValue, setFilterValue] = useState(defaultFilterValue)
  const [filteredRows, setFilteredRows] = useState(null)

  return (
    <div>
      <p>Number of rows: {filteredRows}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onFilterValueChange={setFilterValue}
        filteredRowsCount={setFilteredRows}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(activeCell: Number[2])
default: undefined

Triggered when cell keyboard navigation is enabled (via activeCell or defaultActiveCell) and the user changes the currently active cell.
The first param sent to the callback prop is the value to be used as the new activeCell (an array of size two, the first number being the row index, while the second number is the column index).
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: 300 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

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

  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 />

Fn(activeIndex: Number)
default: undefined

Called whenever the active row is updated. This callback prop is called whether you are using the controlled activeIndex or the uncontrolled defaultActiveIndex or using no active index at all but still have enableKeyboardNavigation=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 people from './people'
import flags from './flags'

const gridStyle = { minHeight: 500 }

const columns = [
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

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>Currently active index: {activeIndex}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        activeIndex={activeIndex}
        onActiveIndexChange={setActiveIndex}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn([...{ column: Object, size: Number, defaultFlex: Number, width: Number }])
default: undefined

Called whenever columns are resized as a result of user interaction (also called for one column, in case just one was resized).
If you want to have a callback prop called for each column, see onColumnResize.
onBatchColumnResize is called with an an array of objects, each having the following properties:
  • column - an object describing the column that has been resized.
    For columns with controlled width, make sure you update the width as a result of the resize.
  • size - a number representing the new size of the column, in pixels
  • flex - indicates whether this column is configured to be flexbile or not.
    For columns with controlled flex, make sure you update the flex as a result of the resize.
  • flexValue - only for flex columns - the value of the flex prop
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

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 onBatchColumnResize = (columnsInfo) => {
  inovua.notification.first.addNotification({
    title: 'Resize occured',
    content: JSON.stringify(columnsInfo.map(info => {
      return {
        column: info.column.name,
        size: info.column.size,
        flex: info.column.flex,
        flexValue: info.column.flexValue
      }
    }))
  })
}

export default () => <div>
  <p>
    Resize a column group
  </p>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
    onBatchColumnResize={onBatchColumnResize}
  />
  <NotificationBoard id="first" />
</div>

Fn(event)
default: undefined

Called when the <ReactDataGrid /> body list is blurred (when it loses focus).
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

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

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [focused, setFocused] = useState(false)

  const onFocus = useCallback((event) => {
    setFocused(true)
  }, [])

  const onBlur = useCallback((event) => {
    setFocused(false)

    inovua.notification.first.addNotification({
      title: 'Grid has been blurred'
    })
  }, [])

  return (
    <div>
      <p>
        Click on the grid and outside it.
      </p>
      <p>
        The grid is {focused ? 'focused' : 'blurred'}.
      </p>
      <ReactDataGrid
        style={gridStyle}
        idProperty="id"
        onFocus={onFocus}
        onBlur={onBlur}
        columns={columns}
        dataSource={people}
      />
      <NotificationBoard id="first" />
    </div>
  );
}

export default () => <App />

Fn(cellProps: Object, event)
default: undefined

Called when the user clicks on a cell.
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: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [cellStyle, setCellStyle] = useState({})
  const [lastClickedCell, setLastClickedCell] = useState(null)
  const [columns, setColumns] = useState(defaultColumns)

  const onCellClick = useCallback((event, cellProps) => {
    const { columnIndex, rowIndex } = cellProps

    const applyColumnStyle = (c, index) => {
      if (index === columnIndex) {
        c = Object.assign({}, c, {
          style: (cellProps) => {
            if (cellProps.rowIndex == rowIndex) {
              return { background: '#ef9a9a', color: '#2e3439' }
            }
          }
        })
      } else {
        c = Object.assign({}, c, { style: null })
      }
      return c
    }

    setLastClickedCell({ columnIndex, rowIndex })
    setColumns(columns.map(applyColumnStyle))
  }, [])

  let cellText = null

  if (lastClickedCell) {
    cellText = <span>Row {lastClickedCell.rowIndex}, column: {lastClickedCell.columnIndex}</span>
  }

  return (
    <div>
      <p>Click on a grid cell!</p>
      <p>Last clicked cell: {cellText}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        cellStyle={cellStyle}
        onCellClick={onCellClick}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(event, cellProps: Object)
default: undefined

Called when the user double clicks on a cell.
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: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [cellStyle, setCellStyle] = useState({})
  const [lastClickedCell, setLastClickedCell] = useState(null)
  const [columns, setColumns] = useState(defaultColumns)

  const onCellDoubleClick = useCallback((event, cellProps) => {
    const { columnIndex, rowIndex } = cellProps

    const applyColumnStyle = (c, index) => {
      if (index === columnIndex) {
        c = Object.assign({}, c, {
          style: (cellProps) => {
            if (cellProps.rowIndex == rowIndex) {
              return { background: '#ef9a9a', color: '#2e3439' }
            }
          }
        })
      } else {
        c = Object.assign({}, c, { style: null })
      }
      return c
    }

    setLastClickedCell({ columnIndex, rowIndex })
    setColumns(columns.map(applyColumnStyle))
  }, [])

  let cellText = null

  if (lastClickedCell) {
    cellText = <span>Row {lastClickedCell.rowIndex}, column: {lastClickedCell.columnIndex}</span>
  }

  return (
    <div>
      <p>Click on a grid cell!</p>
      <p>Last clicked cell: {cellText}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        cellStyle={cellStyle}
        onCellDoubleClick={onCellDoubleClick}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ column, locked })
default: undefined

When specified, updates the value for column.locked.
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 people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

const getColumns = ({ firstColLocked, lastColLocked }) => {
  return [
    { name: 'firstName', header: 'First Name', defaultWidth: 250, locked: firstColLocked },
    { name: 'email', header: 'Email', defaultWidth: 250 },
    { name: 'country', header: 'Country', defaultWidth: 250,
      render: ({ value }) => flags[value] ? flags[value] : value
    },
    { name: 'age', defaultWidth: 250, type: 'number', header: 'Age' },
    {
      id: 'desc',
      header: 'Description',
      defaultWidth: 250,
      render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country,
      locked: lastColLocked
    }
  ]
}

const lockPositions = [
  { value: true, label: 'true' },
  { value: 'start', label: 'start' },
  { value: 'end', label: 'end' },
  { value: false, label: 'false' }
]

const App = () => {
  const [locked, setLocked] = useState(false)
  const [firstColLocked, setFirstColLocked] = useState()
  const [lastColLocked, setLastColLocked] = useState()
  const [columns, setColumns] = useState(getColumns({ firstColLocked, lastColLocked }))

  const onColumnLockedChange = useCallback(({ column, locked }) => {
    setLocked(locked)
  }, [])

  return (
    <div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        onColumnLockedChange={onColumnLockedChange}
      />

      <div style={{marginTop: 20}}>
        <div style={{marginBottom: 20}}>
          Make sure the grid does NOT fit the window, so that column lock and scroll make sense.
        </div>
        <div style={{ marginRight: 8 }}>
          First column lock:
        </div>
        <ComboBox
          autoBlur
          inlineFlex
          idProperty="value"
          displayProperty="label"
          clearIcon={false}
          searchable={false}
          value={firstColLocked}
          onChange={locked => {
            setFirstColLocked(locked)
            setColumns(getColumns({ firstColLocked: locked, lastColLocked }))
          }}
          dataSource={lockPositions}
        />
        <div style={{ marginRight: 8 }}>
            Last column lock:
        </div>
        <ComboBox
          autoBlur
          inlineFlex
          idProperty="value"
          displayProperty="label"
          clearIcon={false}
          searchable={false}
          value={lastColLocked}
          onChange={locked => {
            setLastColLocked(locked)
            setColumns(getColumns({ firstColLocked, lastColLocked: locked }))
          }}
          dataSource={lockPositions}
        />
      </div>
    </div>
  );
}

export default () => <App />

Fn(columnOrder: String[]
default: undefined

Called when the column order is changed via user interaction. This can happen when the <ReactDataGrid /> is configured with reorderColumns=true.
The first argument is the new column order. This prop is often used together with controlled columnOrder.
This function prop is called whether you are specifying a columnOrder 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'
import flags from './flags'

const gridStyle = { minHeight: 550 }

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

const defaultOrder = ['name', 'email', 'country', 'age',]

const App = () => {
  const [reorderColumns, setReorderColumns] = useState(true)
  const [columnOrder, setColumnOrder] = useState(defaultOrder)

  return (
    <div>
      <div>
        <div style={{marginBottom: 20}}>
          First column is fixed, having draggable=false
        </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}
      />
    </div>
  );
}
export default () => <App />

Fn({ column: Object, width: Number, defaultFlex: Number })
default: undefined

Called whenever a column is resized as a result of user interaction.
onColumnResize is called with an object that contains the following properties:
  • column - an object describing the column that has been resized.
    For columns with controlled width, make sure you update the width as a result of the resize.
  • width - a number representing the new size of the column, in pixels. For flexed columns, this will be undefined
  • flex - the flex prop that should be applied to the column. For fixed-sized columns, this will be undefined
    When flexible columns are resized, depending on certain conditions, the <ReactDataGrid /> can choose to make the column fixed size or it can choose to give the column a new flex value.
    The rule you should follow is to always update the column with the width and flex values sent to this method.
When working with column widths & resizing, it's also important to understand how shareSpaceOnResize works.
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: 550 }

const defaultColumns = [
  { name: 'id', header: 'Id', width: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'age', header: 'Age', width: 80, type: 'number' }
]

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
    })

    setColumns(newColumns)
  }, [])

  const keys = [1, 2]
  const sizes = columns.map((c, keys) => c.flex ? null : <li key={keys.toString()}>{c.name}: {c.width}px.</li>)

  return (
    <div>
      <div key={sizes} style={{ marginBottom: 20 }}>Column sizes (only fixed columns): <ul>{sizes}</ul></div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        shareSpaceOnResize
        columns={columns}
        onColumnResize={onColumnResize}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ column, visible })
default: undefined

Called when the column visibility changes.
import React, { useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox'
import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const onColumnVisibleChange = useCallback(({ column, visible }) => {
    inovua.notification.first.addNotification({
      title: 'Visibility changed',
      content: column.name + ' column visibility is set to: ' + visible
    })
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        Change column visibility to test the event
      </div>
      <NotificationBoard id="first" />
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        onColumnVisibleChange={onColumnVisibleChange}
      />
    </div>
  );
}

export default () => <App />

Fn(event)
default: undefined

Called when the user triggers the browser context-menu on the grid. For context menu on row, see onRowContextMenu.
When native DOM events are supported directly on the <ReactDataGrid />, they are called with the event object as the first argument.
Note the difference between onRowContextMenu(rowProps, event) (which is a custom <ReactDataGrid /> event) and onContextMenu(event), which is a native DOM event.
Besides attaching to DOM events as mentioned above, at any time you can render jsx content in cells & headers and attach your events to the custom-rendered content if it better serves your needs.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [contextMenuRow, setContextMenuRow] = useState(null)

  const onContextMenu = useCallback((event, menuProps) => {
    event.preventDefault();

    setContextMenuRow(menuProps.rowIndex);

    inovua.notification.first.addNotification({
      title: 'Context menu event'
    })
  }, [])

  return (
    <div>
      <p>Right-click on a grid row!</p>
      <p>Context menu for row: {contextMenuRow == null? 'none' : contextMenuRow}.</p>
      <NotificationBoard id="first" />
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onContextMenu={onContextMenu}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(row: Object)
default: undefined

If the copy-paste module is enabled, onCopyActiveRowChange callback is triggered when the active row is copied to clipboard.
In order to enable copy-paste module, specify enableClipboard={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 people from './people';

const gridStyle = { minHeight: 550 };

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const App = () => {
  const [enableClipboard, setEnableClipboard] = useState(true)

  const onCopyActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  const onPasteActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  return (
    <div>
      <h3>Grid with copy/paste the active row</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableClipboard}
          onChange={setEnableClipboard}
        >Enable clipboard</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard={enableClipboard}
        onCopyActiveRowChange={onCopyActiveRowChange}
        onPasteActiveRowChange={onPasteActiveRowChange}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn(cells: Object)
default: undefined

If the copy-paste module is enabled, onCopySelectedCellsChange callback is triggered when the selected cells are copied to clipboard.
In order to enable copy-paste module, specify enableClipboard={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 people from './people';

const gridStyle = { minHeight: 550 };

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const App = () => {
  const [enableClipboard, setEnableClipboard] = useState(true)
  const [cellSelection, setCellSelection] = useState({
    '2,name': true,
    '2,city': true,
    '3,name': true,
    '3,city': true,
  });

  const onCopySelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  const onPasteSelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  return (
    <div>
      <h3>Grid with copy/paste the selected cells</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableClipboard}
          onChange={setEnableClipboard}
        >Enable clipboard</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        enableClipboard={enableClipboard}
        onCopySelectedCellsChange={onCopySelectedCellsChange}
        onPasteSelectedCellsChange={onPasteSelectedCellsChange}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn(rows: Object[ ])
default: undefined

If the copy-paste module is enabled, onCopySelectedRowsChange callback is triggered when the selected rows are copied to clipboard.
import React, { useCallback, 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,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps, { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copySelectedRowsToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteSelectedRowsFromClipboard()
    },
  ];
};

const App = () => {
  const [checkboxColumn, setCheckboxColumn] = useState(true);
  const onCopySelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  const onPasteSelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  return (
    <div>
      <h3>Select some rows and then copy/paste from custom context menu</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={checkboxColumn} onChange={setCheckboxColumn}>Checkbox column</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard
        onCopySelectedRowsChange={onCopySelectedRowsChange}
        onPasteSelectedRowsChange={onPasteSelectedRowsChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
        checkboxColumn={checkboxColumn}
      />
    </div>
  );
};

export default () => <App />;

Fn({ columnId, rowIndex, data })
default: undefined

Called when inline editing is canceled by the user.
For more details on inline edit, see inline edit.
When the user navigates away from an editing cell using the Tab key, the value is persisted and onEditComplete is called.
When the user hits the Escape key, the edit is cancelled and onEditCancel is triggered.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [dataSource, setDataSource] = useState(people)
  const [cancelledEdit, setCancelledEdit] = useState('')

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

    setDataSource(data)
  }, [dataSource])

  const edit = cancelledEdit ?
    <p>
      Last cancelled edit: column - {cancelledEdit.columnId}; row - {cancelledEdit.rowIndex}.
    </p> : null

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

export default () => <App />

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

Called when inline editing is completed & confirmed by the user.
For more details on inline edit, see inline edit.
The Grid does not persist the result of the inline edit - so you have to manage that yourself by either updating the local dataSource or by doing a request to a remote api. In the example below we demo updating the local dataSource.
When the user navigates away from an editing cell using the Tab key, the value is persisted and onEditComplete is called.
By default, after an edit is complete, the grid will receive focus, since autoFocusOnEditComplete defaults to true.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

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

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

    setDataSource(data)
  }, [dataSource])

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

export default () => <App />

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

Called when inline editing starts in a <ReactDataGrid /> cell. See onEditCancel or onEditComplete) in order to be notified when an edit is finished.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [lastEdit, setLastEdit] = useState(null)
  const [dataSource, setDataSource] = useState(people)

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

    setDataSource(data)
  }, [dataSource])

  const edit = lastEdit ?
    <p>
      Last started edit: column - {lastEdit.columnId}; row = {lastEdit.rowIndex}
    </p> : null

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

export default () => <App />

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

Called when inline editing is ended in a <ReactDataGrid /> cell. It's called both on edit cancel (see onEditCancel) and edit complete (see onEditComplete). See inline edit for more details on how to configure & use inline editing.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [lastEdit, setLastEdit] = useState(null)

  const onEditStop = useCallback(({ value, columnId, rowIndex }) => {
    setLastEdit({ columnId, rowIndex, value })
  }, [])

  const edit = lastEdit ?
    <div style={{ marginBottom: 20 }}>
      Last edited value: [{lastEdit.columnId}][{lastEdit.rowIndex}] = {lastEdit && lastEdit.value}
    </div> : null

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

export default () => <App />

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

Called when the user is changing the value inside the current editing cell.
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 EditorFeedback = (props) => {
  return (
    <div style={{ margin: '10px 0px'}}>
      Current value: {props.value}.
    </div>
  )
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [dataSource, setDataSource] = useState(people)
  const [value, setValue] = useState('')

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

    setValue('')
    setDataSource(data)
  }, [dataSource])

  const onEditValueChange = useCallback(({ value, columnId , rowIndex }) => {
    setValue(value)
  }, [])

  const onEditStart = useCallback(({ value, columnId, rowIndex }) => {
    setValue(value)
  }, [])

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

export default () => <App />

Fn(enableFiltering)
default: undefined

Called whenever the enableFiltering is changed.
This is called when the user clicks the "Show filtering row"/"Hide filtering row" from the column header menu.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

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

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

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => setEnableFiltering(!enableFiltering)}>
          Toggle enable filtering: {enableFiltering ? 'true' : 'false'}
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onEnableFilteringChange={setEnableFiltering}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
        enableFiltering={enableFiltering}
      />
    </div>
  );
}

export default () => <App />

Fn({ expandedNodes })
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.
Called when a node expand/collapse happens, or when one of the methods that changes the expand state of nodes are called (setNodeExpandedById, toggleNodeExpandById, toggleNodeExpand.
This callback prop is called with an object that has the following properties:
  • expandedNode - an object containing the expanded nodes ids as keys - see expandedNodes
  • data - in case the user clicked to expand/collapse a single node (most probably via the expand/collapse node tool/icon, but could also be a method call), the data will contain the object corresponding to that node
  • index - in case the user clicked to expand/collapse a single node (most probably via the expand/collapse node tool/icon, but could also be a method call), the index will be the index of the node that was just collapsed/expanded
  • id - in case the user clicked to expand/collapse a single node (most probably via the expand/collapse tool/icon of the node, but could also be a method call), the id will be the id of the node that was just collapsed/expanded
  • nodeExpanded - in case the user clicked to expand/collapse a single node (most probably via the expand/collapse tool/icon of the node, but could also be a method call), nodeExpanded will be the new expanded state of that specific node
In case the user clicked to expand/collapse a single node (most probably via the expand/collapse tool/icon of the node, but could also be a method call), the following callback props are also called (before onExpandedNodeChange):
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 />

Fn({ expandedRows, collapsedRows, ... })
default: undefined

Called when a row expand/collapse happens, or when one of the methods that changes the expand state of rows are called (expandAllRows, collapseAllRows, setRowExpandedById, etc).
This callback prop is called with an object that has the following properties:
  • expandedRows - an object containing the expanded rows ids as keys - see expandedRows
  • collapsedRows - in case expandedRows=true, the collapsedRows will be present and contain the collapsed rows ids as keys in this object. See collapsedRows
  • data - in case the user clicked to expand/collapse a single row (most probably via the expand/collapse button of the row, but could also be a method call), the data will contain the object corresponding to that row
  • index - in case the user clicked to expand/collapse a single row (most probably via the expand/collapse button of the row, but could also be a method call), the index will be the index of the row that was just collapsed/expanded
  • id - in case the user clicked to expand/collapse a single row (most probably via the expand/collapse button of the row, but could also be a method call), the id will be the id of the row that was just collapsed/expanded
  • rowExpanded - in case the user clicked to expand/collapse a single row (most probably via the expand/collapse button of the row, but could also be a method call), rowExpanded will be the new expanded state of that specific row
In case the user clicked to expand/collapse a single row (most probably via the expand/collapse button of the row, but could also be a method call), the following callback props are also called (before onExpandedRowsChange):
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, index) => {
          return <tr key={index}>
            <td>{name}</td>
            <td>{data[name]}</td>
          </tr>
        })}
      </tbody>
    </table>
  </div>
}

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [expandedRowsFlag, setExpandedRowsFlag] = useState(null)
  const [collapsedRowsFlag, setCollapsedRowsFlag] = useState(null)

  const onExpandedRowsChange = useCallback(({ expandedRows, collapsedRows }) => {
    setExpandedRowsFlag(expandedRows)
    setCollapsedRowsFlag (collapsedRows)
  }, [])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button
          style={{ marginRight: 10 }}
          onClick={() => gridRef.current.expandAllRows()}
        >
          Expand all
        </Button>
        <Button onClick={() => gridRef.current.collapseAllRows()}>
          Collapse all
        </Button>
      </div>
      <ReactDataGrid
        handle={setGridRef}
        idProperty="id"
        onExpandedRowsChange={onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(filterValue)
default: undefined

Called whenever the filterValue is changed.
This is called for both controlled (filterValue) and uncontrolled (defaultFilterValue) filter values.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

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

const App = () => {
  const [filterValue, setFilterValue] = useState(defaultFilterValue)

  return (
    <div>
      <p>Current filter value: {JSON.stringify(filterValue, null, 2)}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onFilterValueChange={setFilterValue}
        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 />

Fn(event)
default: undefined

Called when the <ReactDataGrid /> is focused by the user.
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 = { marginTop: 10, minHeight: 300 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [focused, setFocused] = useState(false)

  const onFocus = useCallback((event) => {
    setFocused(true)
  }, [])

  const onBlur = useCallback((event) => {
    setFocused(false)
  }, [])

  return (
    <div>
      <p>
        Click on the grid and outside it.
      </p>
      <p>
        The grid is {focused ? 'focused' : 'blurred'}.
      </p>
      <ReactDataGrid
        style={gridStyle}
        idProperty="id"
        onFocus={onFocus}
        onBlur={onBlur}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(groupBy)
default: undefined

Called whenever grouping changes. The user can change a grouping by dragging a column header on the grouping toolbar (the toolbar is only displayed when groupBy is specified) or by removing a column from grouping (either via the clear icon or by dragging the column group item back into the grid header).
When controlled groupBy, make sure you use the onGroupByChange callback prop to update the <ReactDataGrid /> grouping accordingly.
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 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, groupBy: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'First Name', groupBy: false, defaultFlex: 1 },
  { name: 'lastName', header: 'Last Name', defaultFlex: 1 },
  {
    name: 'permissionToCall',
    header: 'Permission to call',
    flex: 1,
    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'])}>Group by permission to call</Button></p>
      <p><Button onClick={() => setGroupBy([])}>Ungroup</Button></p>
      <div style={{marginBottom: 20}}>
        Current grouping: {JSON.stringify(groupBy)}
      </div>
      <ReactDataGrid
        defaultLimit={15}
        pagination
        idProperty="id"
        style={gridStyle}
        groupBy={groupBy}
        onGroupByChange={setGroupBy}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(collapsedGroups: Object | true, expandedGroups: Object | true)
default: undefined

Called whenever the user expands/collapses a group in the <ReactDataGrid />. Often used together with the controlled collapsed or the uncontrolled defaultCollapsed.
When using the controlled collapsedGroups/expandedGroups, make sure you update the collapsedGroups/expandedGroups value when onGroupCollapseChange is triggered.
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: 500 }

const columns = [
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

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

  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 />

Fn({ data: Object, dropIndex: Number, dropGroup: String })
default: undefined

When row reorder on groups is enabled, on mouse up onGroupRowReorderEnd callback is triggered.
This callback prop is called with an object that has the following properties:
  • data - the row data at the drop index.
  • dropIndex - the drop index.
  • dropGroup - the drop group.
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: 750,
};

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

const renderRowReorderProxy = ({data}) => {
  return <div style={{ paddingLeft: 30 }}>ID: {data.id} - Name: {data.name}</div>
}

const App = () => {
  const [defaultGroupBy, setDefaultGroupBy] = useState(['country']);
  const [
    allowRowReorderBetweenGroups,
    setAllowRowReorderBetweenGroups,
  ] = useState(true);
  const [movingGroup, setMovingGroup] = useState(null);

  const onGroupRowReorderStart = useCallback(({ data, dragIndex, dragGroup }) => {
    setMovingGroup(dragGroup);
  }, []);

  const onGroupRowReorderEnd = useCallback(({ data, dropIndex, dropGroup }) => {
    setMovingGroup(dropGroup);
    setTimeout(() => setMovingGroup(null), 2000);
  }, []);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          theme="default-dark"
          checked={allowRowReorderBetweenGroups}
          onChange={setAllowRowReorderBetweenGroups}
        >
          allowRowReorderBetweenGroups
        </CheckBox>
      </div>

      <p>{movingGroup ? 'The ' + movingGroup + ' group is moving.' : 'No group is moved.'}</p>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={defaultGroupBy}
        columns={columns}
        dataSource={people}
        rowReorderColumn
        allowRowReorderBetweenGroups={allowRowReorderBetweenGroups}
        renderRowReorderProxy={renderRowReorderProxy}
        onGroupRowReorderStart={onGroupRowReorderStart}
        onGroupRowReorderEnd={onGroupRowReorderEnd}
      />
    </div>
  );
};

export default () => <App />;
             

Fn({ data: Object, dragIndex: Number, dragGroup: String })
default: undefined

When row reorder on groups is enabled, on mouse down onGroupRowReorderStart callback is triggered.
This callback prop is called with an object that has the following properties:
  • data - the row data at the drag index.
  • dragIndex - the index to which drag begins.
  • dragGroup - the group from which the drag begins.
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: 750,
};

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

const renderRowReorderProxy = ({data}) => {
  return <div style={{ paddingLeft: 30 }}>ID: {data.id} - Name: {data.name}</div>
}

const App = () => {
  const [defaultGroupBy, setDefaultGroupBy] = useState(['country']);
  const [
    allowRowReorderBetweenGroups,
    setAllowRowReorderBetweenGroups,
  ] = useState(true);
  const [movingGroup, setMovingGroup] = useState(null);

  const onGroupRowReorderStart = useCallback(({ data, dragIndex, dragGroup }) => {
    setMovingGroup(dragGroup);
  }, []);

  const onGroupRowReorderEnd = useCallback(({ data, dropIndex, dropGroup }) => {
    setMovingGroup(dropGroup);
    setTimeout(() => setMovingGroup(null), 2000);
  }, []);

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          theme="default-dark"
          checked={allowRowReorderBetweenGroups}
          onChange={setAllowRowReorderBetweenGroups}
        >
          allowRowReorderBetweenGroups
        </CheckBox>
      </div>

      <p>{movingGroup ? 'The ' + movingGroup + ' group is moving.' : 'No group is moved.'}</p>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={defaultGroupBy}
        columns={columns}
        dataSource={people}
        rowReorderColumn
        allowRowReorderBetweenGroups={allowRowReorderBetweenGroups}
        renderRowReorderProxy={renderRowReorderProxy}
        onGroupRowReorderStart={onGroupRowReorderStart}
        onGroupRowReorderEnd={onGroupRowReorderEnd}
      />
    </div>
  );
};

export default () => <App />;
             

Fn(event)
default: undefined

Called when the keydown event happens on the <ReactDataGrid />.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [lastKey, setLastKey] = useState(null)

  const onKeyDown = useCallback(event => {
    setLastKey(event.key)
  }, [])

  return (
    <div>
      <p>Focus the grid and press some printable characters!</p>
      <p>Last pressed key: "{lastKey || 'unknown'}".</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onKeyDown={onKeyDown}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(limit: Number)
default: undefined

Called when the limit is updated.
The default pagination toolbar has a ComboBox displaying a choice of page-sizes. When the user changes the page size from the ComboBox, onLimitChange is called.
When using the controlled limit 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.
This is called whether you are using the controlled limit or the uncontrolled defaultLimit.
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: 300, marginTop: 10 }

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

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 [limit, setLimit] = useState(10)

  const dataSource = useCallback(loadData, [])

  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>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        limit={limit}
        onLimitChange={setLimit}
        pagination
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(loading: Bool)
default: undefined

Called when the loading state changes.
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', header: 'Name', defaultFlex: 1 },
  { name: 'age', header: 'Age' }
]

const App = () => {
  const [loading, setLoading] = useState(false)
  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: 'Angela Berkley', age: 44, id: 5 },
          { name: 'Franklin Richardson', age: 37, id: 6 }
        ])
      }, 1000)
    })

    setLoading(true)
    setDataSource(data)
  }, [])

  return (
    <div>
      <p>
        <Button onClick={() => mockTimeConsumingLoad()}>
          Start long loading...
        </Button>
      </p>
      <p>
        Loading: {loading.toString()}
      </p>
      <ReactDataGrid
        style={{ marginTop: 10, minHeight: 300 }}
        idProperty="id"
        columns={columns}
        dataSource={dataSource}
        onLoadingChange={setLoading}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, id, index })
default: undefined

Called when a single node is collapsed.
This callback prop is not called when a bulk collapse action is performed (via a method call affecting multiple nodes).
Returning false will cancel the action and the node will not be collapsed.
This callback prop is called with an object that has the following properties:
  • data - will contain the object corresponding to the node
  • index - will be the index of the node
  • id - the id of the node
  • nodeProps - an object with information about the current node - depth, parentId, path, etc
For node expand, see onNodeExpand.
For a more general notification, see onExpandedNodesChange.
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 defaultExpandedNodes = { 3: true, '3/1': true}

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

const App = () => {
  const [lastCollapsedId, setLastCollapsedId] = useState(null)

  const onNodeCollapse = useCallback(({ id }) => {
    setLastCollapsedId(id)
  })

  return (
    <div>
      <p>
        Last collapsed id: {lastCollapsedId == null ? 'none': lastCollapsedId}.
      </p>
      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        onNodeCollapse={onNodeCollapse}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, id, index })
default: undefined

Called when a single node is expanded.
This callback prop is not called when a bulk expand action is performed (via a method call affecting multiple nodes).
Returning false will cancel the action and the node will not be expanded.
This callback prop is called with an object that has the following properties:
  • data - will contain the object corresponding to the node
  • index - will be the index of the node
  • id - the id of the node
  • nodeProps - an object with information about the current node - depth, parentId, path, etc
For node collapse, see onNodeCollapse.
For a more general notification, see onExpandedNodesChange.
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 defaultExpandedNodes = { 3: true, '3/1': true}

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

const App = () => {
  const [lastExpandedId, setLastExpandedId] = useState(null)

  const onNodeExpand = useCallback(({ id }) => {
    setLastExpandedId(id)
  }, [])

  return (
    <div>
      <p>
        Last expanded id: {lastExpandedId == null ? 'none': lastExpandedId}.
      </p>
      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        onNodeExpand={onNodeExpand}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, id, index })
default: undefined

Called when a single node is expanded or collapsed.
This callback prop is not called when a bulk collapse/expand action is performed (via a method call affecting multiple nodes).
Returning false will cancel the action and the node will not be expanded or collapsed.
This callback prop is called with an object that has the following properties:
  • expandedNodes - an object containing the expanded nodes ids as keys - see expandedNodes
  • data - will contain the object corresponding to the node
  • index - will be the index of the node
  • id - the id of the node
  • nodeProps - an object with information about the current node - depth, parentId, path, etc
  • nodeExpanded - the new expanded state of the node
For node expand only, see onNodeExpand.
For node collapse only, see onNodeCollapse.
For a more general notification, see onExpandedNodesChange.
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 defaultExpandedNodes = { 3: true, '3/1': true}

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

const App = () => {
  const [lastNodeId, setLastNodeId] = useState(null)
  const [nodeExpanded, setNodeExpanded] = useState(null)

  const onNodeExpandChange = useCallback(({ id: lastNodeId, nodeExpanded }) => {
    setLastNodeId(lastNodeId)
    setNodeExpanded(nodeExpanded)
  }, [])

  return (
    <div>
    <p>
      Last node that was {nodeExpanded ? 'expanded': 'collapsed'}: {lastNodeId == null ? 'none': lastNodeId}.
    </p>
      <ReactDataGrid
        treeColumn="name"
        defaultExpandedNodes={defaultExpandedNodes}
        onNodeExpandChange={onNodeExpandChange}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />
    </div>
  );
}

export default () => <App />

Fn(row: Object)
default: undefined

If the copy-paste module is enabled, onPasteActiveRowChange callback is triggered when the active row is pasted from clipboard.
In order to enable copy-paste module, specify enableClipboard={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 people from './people';

const gridStyle = { minHeight: 550 };

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const App = () => {
  const [enableClipboard, setEnableClipboard] = useState(true)

  const onCopyActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  const onPasteActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  return (
    <div>
      <h3>Grid with copy/paste the active row</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableClipboard}
          onChange={setEnableClipboard}
        >Enable clipboard</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard={enableClipboard}
        onCopyActiveRowChange={onCopyActiveRowChange}
        onPasteActiveRowChange={onPasteActiveRowChange}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn(cells: Object)
default: undefined

If the copy-paste module is enabled, onPasteSelectedCellsChange callback is triggered when the selected cells are pasted from clipboard.
In order to enable copy-paste module, specify enableClipboard={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 people from './people';

const gridStyle = { minHeight: 550 };

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const App = () => {
  const [enableClipboard, setEnableClipboard] = useState(true)
  const [cellSelection, setCellSelection] = useState({
    '2,name': true,
    '2,city': true,
    '3,name': true,
    '3,city': true,
  });

  const onCopySelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  const onPasteSelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  return (
    <div>
      <h3>Grid with copy/paste the selected cells</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableClipboard}
          onChange={setEnableClipboard}
        >Enable clipboard</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        enableClipboard={enableClipboard}
        onCopySelectedCellsChange={onCopySelectedCellsChange}
        onPasteSelectedCellsChange={onPasteSelectedCellsChange}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn(rows: Object[ ])
default: undefined

If the copy-paste module is enabled, onCopySelectedRowsChange callback is triggered when the selected rows are pasted from clipboard.
import React, { useCallback, 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,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps, { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copySelectedRowsToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteSelectedRowsFromClipboard()
    },
  ];
};

const App = () => {
  const [checkboxColumn, setCheckboxColumn] = useState(true);
  const onCopySelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  const onPasteSelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  return (
    <div>
      <h3>Select some rows and then copy/paste from custom context menu</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={checkboxColumn} onChange={setCheckboxColumn}>Checkbox column</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard
        onCopySelectedRowsChange={onCopySelectedRowsChange}
        onPasteSelectedRowsChange={onPasteSelectedRowsChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
        checkboxColumn={checkboxColumn}
      />
    </div>
  );
};

export default () => <App />;

(computedPropsRef: MutableRef) => void
default: undefined

This callback prop is called when the DataGrid layout is ready (columns are sized, the grid size is known).
This prop could prove useful in tests/CI environments, to make sure you don't run your tests too early.
Can also be used to get a reference to the grid (more exactly, a ref to the grid computed props) when the grid component is ready for use
The first argument passed to this function is a React ref object.
Please do not store a reference to computedPropsRef.current - as the object is changed on every render. Rather, keep a reference to computedPropsRef - which is React ref.
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', header: 'Name', defaultFlex: 1 },
  { name: 'size', header: 'Size', defaultWidth: 120 }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [expandedNodes, setExpandedNodes] = useState(defaultExpandedNodes)
  const [dataSource, setDataSource] = useState(treeData)

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

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => gridRef.current.setItemPropertyAt(0, 'name', 'Apps')}>
          Set "name" property for first node to "Apps"
        </Button>
      </div>
      <div style={{ marginBottom: 20 }}>
        <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>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        treeColumn="name"
        expandedNodes={expandedNodes}
        onExpandedNodesChange={onExpandedNodesChange}
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(rowProps)|React.Node
default: undefined

Instead of using renderRow we recommend you use onRenderRow(rowProps), which has the same benefit of being called with the rowProps object and be able to modify it, but it discards the returned value, so the default row rendering happens. This ensures all <ReactDataGrid /> features will probably work the same unless you change the layout related styling props.
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 onRenderRow = ({ data, style }) => {
  const { age } = data
  if (age > 30) {
    if (age > 35) {
      style.color = '#ef9a9a'
    } else {
      style.color = '#7986cb'
    }
  }
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Customized row rendering, computed by age
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onRenderRow={onRenderRow}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(reservedViewportWidth: Number)
default: undefined

Called when reservedViewportWidth changes as a result of user interaction (user resizes columns).
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultFlex: 2,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'email', header: 'Email', defaultFlex: 3 },
]

const App = () => {
  const [reservedViewportWidth, setReservedViewportWidth] = useState()

  return (
    <div>
      <div style={{marginBottom: 20}}>
        Columns with flex values of 1, 2, and 3
      </div>
      <div style={{marginBottom: 20}}>
        Reserved viewport width: {reservedViewportWidth ? reservedViewportWidth : 'none'}. Resize/shrink columns and then click the reset button below.
      </div>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => setReservedViewportWidth(null)}>
          Clear reserved width
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        reservedViewportWidth={reservedViewportWidth}
        onReservedViewportWidthChange={setReservedViewportWidth}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(rowProps: Object, event)
default: undefined

Called when the user clicks on a row.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [lastClickedRow, setLastClickedRow] = useState(null)

  const onRowClick = useCallback((rowProps, event) => {
    setLastClickedRow(rowProps.rowIndex)
  }, [])

  return (
    <div>
      <p>Click on a grid row!</p>
      <p>Last clicked row: {lastClickedRow === null? 'none' : lastClickedRow}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onRowClick={onRowClick}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, id, index })
default: undefined

Called when a single row is collapsed.
This callback prop is not called when a bulk collapse action is performed (via collapseAllRows).
Returning false will cancel the action and the row will not be collapsed.
This callback prop is called with an object that has the following properties:
  • data - will contain the object corresponding to the row
  • index - will be the index of the row
  • id - the id of the row
For row expand, see onRowExpand.
For a more general notification, see onExpandedRowsChange.
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 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 defaultExpandedRows = { 1: true, 2: true}

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

const App = () => {
  const [lastCollapsedId, setLastCollapsedId] = useState(null)

  const onRowCollapse = useCallback(({ id }) => {
    setLastCollapsedId(id)
  }, [])

  return (
    <div>
      <p>
        Last collapsed id: {lastCollapsedId == null ? 'none': lastCollapsedId}.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        onRowCollapse={onRowCollapse}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(rowProps: Object, event)
default: undefined

Called when the user triggers the browser context-menu on a grid row.
See renderRowContextMenu for a custom row context menu demo.
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 columns = [
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [contextMenuRow, setContextMenuRow] = useState(null)

  const onRowContextMenu = useCallback((rowProps, event) => {
    event.preventDefault()
    setContextMenuRow(rowProps.rowIndex)
  }, [])

  return (
    <div>
      <p>Right-click on a grid row!</p>
      <p>Context menu row: {contextMenuRow == null? 'none' : contextMenuRow}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onRowContextMenu={onRowContextMenu}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(event, cellProps: Object)
default: undefined

Called when the user double clicks on a row.
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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [lastClickedRow, setLastClickedRow] = useState(null)

  const onRowDoubleClick = useCallback((event, rowProps) => {
    setLastClickedRow(rowProps.rowIndex)
  }, [])

  return (
    <div>
      <p>Click on a grid row!</p>
      <p>Last clicked row: {lastClickedRow === null? 'none' : lastClickedRow}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        onRowDoubleClick={onRowDoubleClick}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, id, index })
default: undefined

Called when a single row is expanded.
This callback prop is not called when a bulk expand action is performed (via expandAllRows).
Returning false will cancel the action and the row will not be expanded.
This callback prop is called with an object that has the following properties:
  • data - will contain the object corresponding to the row
  • index - will be the index of the row
  • id - the id of the row
For row collapse, see onRowCollapse.
For a more general notification, see onExpandedRowsChange.
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 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 defaultExpandedRows = {}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [lastExpandedId, setLastExpandedId] = useState(null)

  const onRowExpand = useCallback(({ id }) => {
    setLastExpandedId(id)
  })

  return (
    <div>
      <p>
        Last expanded id: {lastExpandedId == null ? 'none': lastExpandedId}.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        onRowExpand={onRowExpand}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({ data, id, index, collapsedRows, expandedRows, rowExpanded })
default: undefined

Called when a single row is expanded or collapsed.
This callback prop is not called when a bulk expand/collapse action is performed (via expandAllRows or collapseAllRows).
Returning false will cancel the action and the row will not be expanded or collapsed.
This callback prop is called with an object that has the following properties:
  • expandedRows - an object containing the expanded rows ids as keys - see expandedRows
  • collapsedRows - in case expandedRows=true, the collapsedRows will be present and contain the collapsed rows ids as keys in this object. See collapsedRows
  • data - will contain the object corresponding to the row
  • index - will be the index of the row
  • id - the id of the row
  • rowExpanded - the new expanded state of the row
For row collapse only, see onRowCollapse.
For row expand only, see onRowExpand.
For a more general notification, see onExpandedRowsChange.
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 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 defaultExpandedRows = { 1: true }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  const [lastRowId, setLastRowId] = useState(null)
  const [rowExpanded, setRowExpanded] = useState(null)

  const onRowExpandChange = useCallback(({ id: lastRowId, rowExpanded }) => {
    setLastRowId(lastRowId)
    setRowExpanded(rowExpanded)
  }, [])

  return (
    <div>
      <p>
        Last row that was {rowExpanded ? 'expanded': 'collapsed'}: {lastRowId == null ? 'none': lastRowId}.
      </p>
      <ReactDataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        onRowExpandChange={onRowExpandChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn({data, dragRowIndex, insertRowIndex })
default: undefined

Called when the <ReactDataGrid /> is configured with row reordering and the user reorders rows via drag and drop - more specifically, called when the row is dropped.
When the grid is sorted, filtered, grouped or pivoted, the row reordering does not work, as it would be confusing.
When the dataSource is an array or a promise, if the grid is configured with row reordering, if no onRowReorder is specified, the rows will be reordered internally in the dataSource.
However, if the dataSource is a function, you have to specify onRowReorder({ data, dragRowIndex, insertRowIndex }) and implement the reordering logic yourself.
import React, { useCallback, useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

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

const gridStyle = { minHeight: 550 }

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

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

  const onRowReorder = useCallback(({ data, dragRowIndex, insertRowIndex }) => {
    let newData = moveXBeforeY([...dataSource], dragRowIndex, insertRowIndex);

    setDataSource(newData);
  }, [dataSource])

  return (
    <ReactDataGrid
      idProperty="id"
      style={gridStyle}
      rowHeight={40}
      onRowReorder={onRowReorder}
      columns={columns}
      dataSource={dataSource}
    />
  )
}

export default () => <App />

Fn({ data: Object, dropIndex: Number })
default: undefined

When row reorder is enabled, onRowReorderEnd callback is triggered.
This callback prop is called with an object that has the following properties:
  • data - the row data at the drop index.
  • dropIndex - the drop index.
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 renderRowReorderProxy = ({data}) => {
  return <div style={{ paddingLeft: 30 }}>ID: {data.id} - Name: {data.name}</div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id' },
  { name: 'name', defaultWidth: 120, header: 'Name', },
  { name: 'country', defaultWidth: 120, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultWidth: 120, header: 'Age' }
];

const App = () => {
  const [movingRow, setMovingRow] = useState(null);

  const onGroupRowReorderStart = useCallback(({ data, dragIndex }) => {
    setMovingRow(dragIndex);
  }, []);

  const onGroupRowReorderEnd = useCallback(({ data, dropIndex }) => {
    setMovingRow(dragIndex);
    setTimeout(() => setMovingRow(null), 2000);
  }, []);

  return (
    <div>
      <p>{movingRow != null ? 'The ' + movingRow + ' is moving.' : 'No row is moved.'}</p>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowHeight={40}
        rowReorderColumn
        renderRowReorderProxy={renderRowReorderProxy}
        columns={columns}
        dataSource={people}
        onGroupRowReorderStart={onGroupRowReorderStart}
        onGroupRowReorderEnd={onGroupRowReorderEnd}
      />
    </div>
  )
}

export default () => <App />

Fn({ data: Object, dragIndex: Number })
default: undefined

When row reorder is enabled, onRowReorderStart callback is triggered.
This callback prop is called with an object that has the following properties:
  • data - the row data at the drag index.
  • dragIndex - the index to which drag begins.
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 renderRowReorderProxy = ({data}) => {
  return <div style={{ paddingLeft: 30 }}>ID: {data.id} - Name: {data.name}</div>
}

const columns = [
  { name: 'id', defaultWidth: 60, header: 'Id' },
  { name: 'name', defaultWidth: 120, header: 'Name', },
  { name: 'country', defaultWidth: 120, header: 'Country',
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', type: 'number', defaultWidth: 120, header: 'Age' }
];

const App = () => {
  const [movingRow, setMovingRow] = useState(null);

  const onGroupRowReorderStart = useCallback(({ data, dragIndex }) => {
    setMovingRow(dragIndex);
  }, []);

  const onGroupRowReorderEnd = useCallback(({ data, dropIndex }) => {
    setMovingRow(dragIndex);
    setTimeout(() => setMovingRow(null), 2000);
  }, []);

  return (
    <div>
      <p>{movingRow != null ? 'The ' + movingRow + ' is moving.' : 'No row is moved.'}</p>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowHeight={40}
        rowReorderColumn
        renderRowReorderProxy={renderRowReorderProxy}
        columns={columns}
        dataSource={people}
        onGroupRowReorderStart={onGroupRowReorderStart}
        onGroupRowReorderEnd={onGroupRowReorderEnd}
      />
    </div>
  )
}

export default () => <App />

Fn({ selected, data, unselected })
default: undefined

This function prop is called when row selection is enabled (whether you specify a controlled selected or an uncontrolled defaultSelected or the enableSelection prop).
When the user interacts with the <ReactDataGrid /> and changes the current selection, onSelectionChange is called with an object, that has the following keys:
  • data - an array that holds all the selected items.
  • selected - an object with the selected items, keyed using their id properties as specified by idProperty.
  • unselected - an object with unselected items, keyed just like the selected property. This is only used when remote dataSource is used, since in this situation there are cases when the<ReactDataGrid /> needs to store unselected items rather than selected ones (eg: user selects all items, and then unselects one or two rows - selected becomes true, while unselected stores the two unselected ids).
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 columns = [
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [selected, setSelected] = useState({ 1: true, 2: true })

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

  return (
    <div>
      <p>
        Selected rows: {selected == null ? 'none' : JSON.stringify(Object.keys(selected))}.
      </p>
      <p>
        You can shift+click grid rows to select multiple rows
      </p>
      <ReactDataGrid
        idProperty="id"
        multiSelect
        selected={selected}
        onSelectionChange={onSelectionChange}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(skip: Number)
default: undefined

Called when the skip is updated. When the user goes to the next page this callback prop is called.
When using the controlled skip, 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.
This is called whether you are using the controlled skip or the uncontrolled defaultSkip.
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: 300, marginTop: 10 }

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

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 [skip, setSkip] = useState(50)

  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <p>Try to navigate to the next pages to see the skip change. Loads page 2 on initial load</p>
      <p>Current skip: {skip}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        skip={skip}
        onSkipChange={setSkip}
        pagination
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(sortInfo)
default: undefined

Called whenever the sorting changes. This is called even if you are using controlled or uncontrolled sorting.
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: 500 }

const sort = (arr, sortInfo) => {
  arr = [].concat(arr)
  if (!sortInfo) {
    return arr
  }
  return arr.sort((o1, o2) => {
    const v1 = o1[sortInfo.name]
    const v2 = o2[sortInfo.name]

    const result = sortInfo.type == 'number'
      ? v1 - v2
      : v1.localeCompare(v2)

    return result * sortInfo.dir
  })
}

const columns = [
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 },
  {
    id: 'desc',
    header: 'Description',
    minWidth: 150,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const defaultSortInfo = { name: 'age', type: 'number', dir: 1 }
const initialData = sort(people, defaultSortInfo)

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

  const onSortInfoChange = useCallback((value) => {
    const newSort = value ? { type: value.type, name: value.name, dir: value.dir } : value
    setDataSource(sort(people, value))
    setSortInfo(newSort)
  }, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        Current sort info: {sortInfo ? <code>{JSON.stringify(sortInfo, null, 2)}</code>: 'none'}.
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        sortInfo={sortInfo}
        columns={columns}
        dataSource={dataSource}
        onSortInfoChange={onSortInfoChange}
      />
    </div>
  );
}

export default () => <App />

Fn({ updatedTreeData: Array[Object] })
default: undefined

Called when a row is dropped and returns the new data source computed after reorder.
For enabling row reorder on tree grid, rowReorderColumn and enableTreeRowReorder should both be 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';

const gridStyle = { minHeight: 750 };

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' },
    ],
  },
  { id: 4, name: 'Movies' },
];

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

const App = () => {
  const onTreeRowReorderEnd = useCallback(({ updatedTreeData: data }) => {
    console.log(data);
  }, []);

  return (
    <div>
      <h3>TreeGrid with onTreeRowReorderEnd demo</h3>

      <ReactDataGrid
        treeColumn="name"
        theme="default-dark"
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
        defaultExpandedNodes={{ 1: true, 2: true, 3: true, '3/1': true }}
        rowReorderColumn
        enableTreeRowReorder
        onTreeRowReorderEnd={onTreeRowReorderEnd}
      />
    </div>
  );
};

export default () => <App />;

Fn(rowProps)|React.Node
default: undefined

The DataGrid can also be configured to use a custom row rendering function, using the renderRow(rowProps) function prop.
If this function returns undefined, the default rendering is used. Although returning undefined, it can still be useful since it can control & change values in the rowProps, object it receives as first parameter. For example, it can add styles to rowProps.style or can manipulate classNames by modifying rowProps.className. Or it can add other events or DOM properties to the rowProps object.
In case it returns a React.Node, that node is rendered instead of the default implementation.
When returning a custom React.Node from renderRow, be aware that you are probably breaking virtualization or other useful <ReactDataGrid /> features. So make sure you know what you're doing!
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 renderRow = ({ data, style }) => {
  const { age } = data
  if (age > 30) {
    if (age > 35) {
      style.color = '#ef9a9a'
    } else {
      style.color = '#7986cb'
    }
  }
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80 },
  { name: 'name', header: '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', type: 'number', defaultFlex: 1 }
]

const App = () => {
  return (
    <div>
      <div style={{marginBottom: 20}}>
        Customized row rendering, computed by age
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        renderRow={renderRow}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Styling props

string
default: undefined

Specifies a CSS class string for active row indicator.
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', header: 'Id', defaultVisible: false, defaultWidth: 60, 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', defaultFlex: 1, type: 'number' }
];

const App = () => {
  const [showActiveRowIndicator, setShowActiveRowIndicator] = useState(true);

  return (
    <div>
      <h3>DataGrid with custom active row indicator</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={showActiveRowIndicator}
          onChange={setShowActiveRowIndicator}>
            Enable active row indicator
        </CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        enableSelection
        showActiveRowIndicator={showActiveRowIndicator}
        activeRowIndicatorClassName="active-row-border"
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

A css className to be applied to 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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    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}
        className="global-datagrid-3px-tomato-border"
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

Specifies a custom column hover className, if enableColumnHover is enabled.
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',
    defaultWidth: 60,
    type: 'number',
  },
  { name: 'name', header: 'Name', defaultWidth: 100 },
  {
    name: 'country',
    header: 'Country',
    defaultWidth: 100,
    render: ({ value }: { value: string }) =>
      flags[value] ? flags[value] : value,
  },
  {
    name: 'city',
    header: 'City',
    defaultWidth: 120,
    enableColumnHover: false
  },
  {
    name: 'age',
    header: 'Age',
    defaultWidth: 100,
    type: 'number',
    enableColumnHover: true
  },
];

const App = () => {
  const [enableColumnHover, setEnableColumnHover] = useState(true)

  return (
    <div>
      <h3>Grid with custom column hover class</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={enableColumnHover}
          onChange={setEnableColumnHover}
        >Enable column hover</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        enableColumnHover={enableColumnHover}
        columnHoverClassName="custom-column-hover-class-name"
      />
    </div>
  );
};

export default () => <App />;

Number
default: 9

Specifies the width of the resize handle used when resizing columns.
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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name - maxWidth: 300', defaultFlex: 2, maxWidth: 300 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City - flex 3', defaultFlex: 3 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  return (
    <div>
      <p>Try resizing a column.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columnResizeHandleWidth={20}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: undefined

Specifies a className to a cell.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import './index.global.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: 'name', header: 'Name', defaultFlex: 1, cellProps: { className: 'global-row-color-tomato' } },
  { name: 'country', header: 'Country', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1, cellProps: { className: 'global-row-color-blue' }},
  { name: 'age', header: 'Age', defaultFlex: 1 }
]

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

export default () => <App />

Object
default: undefined

A style object for all cells in a specific column. NOT applied to the column header.
If you want to apply a style to both the column cells and to the column header, use columns.style.
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 blueStyle = {
  color: '#7986cb'
}

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

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

export default () => <App />

String | Fn(cellProps: Object)
default: undefined

Specifies a className to a column.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import './index.global.css'

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

const gridStyle = { minHeight: 550 }

const countryClass = "global-row-color-tomato"
const blueColor = "global-row-color-blue"

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

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

export default () => <App />

String
default: undefined

Specifies a custom className to the column header.
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import './index.global.css'

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

const gridStyle = { minHeight: 550 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1, headerProps: { className : 'global-row-color-blue' } },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1, headerProps: { className: 'global-row-color-tomato' } },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

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

export default () => <App />

Object
default: undefined

Specifies a custom style to the column header.
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 redStyle = {
  color: '#ef9a9a'
}
const blueColor = {
  color: '#7986cb'
}

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

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

export default () => <App />

Object|Fn(cellProps: Object)
default: undefined

A style object for all cells in a specific column. Also applied to the column header.
If you only want to apply a style to column cells only, and not to the column header, use cellProps.style.
The value of this prop can also be a function - which is being called with the cellProps of the current cell being rendered.
If a function is specified, the return style object is only applied to column cells, and not to the column header.
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 cityStyle = ({ data }) => {
  const colorMap = {
    ca: '#ef9a9a',
    uk: '#7986cb'
  }

  return {
    color: colorMap[data.country] || 'orange',
    textTransform: 'uppercase'
  }
}

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

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

export default () => <App />
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: 'firstName', header: 'Fist Name', defaultFlex: 1 },
  { name: 'country', header: 'Country', defaultWidth: 100,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'age', header: 'Age', defaultWidth: 70, type: 'number' },
  {
    id: 'desc',
    header: 'Description',
    defaultWidth: 250,
    render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
  }
]

const App = () => {
  const [cellStyle, setCellStyle] = useState({})
  const [lastClickedCell, setLastClickedCell] = useState(null)
  const [columns, setColumns] = useState(defaultColumns)

  const onCellClick = useCallback((event, cellProps) => {
    const { columnIndex, rowIndex } = cellProps

    const applyColumnStyle = (c, index) => {
      if (index === columnIndex) {
        c = Object.assign({}, c, {
          style: (cellProps) => {
            if (cellProps.rowIndex == rowIndex) {
              return { background: '#ef9a9a', color: '#2e3439' }
            }
          }
        })
      } else {
        c = Object.assign({}, c, { style: null })
      }
      return c
    }

    setLastClickedCell({ columnIndex, rowIndex })
    setColumns(columns.map(applyColumnStyle))
  }, [])

  let cellText = null

  if (lastClickedCell) {
    cellText = <span>Row {lastClickedCell.rowIndex}, column: {lastClickedCell.columnIndex}</span>
  }

  return (
    <div>
      <p>Click on a grid cell to see the cellStyle applied!</p>
      <p>Last clicked cell: {cellText}.</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        cellStyle={cellStyle}
        onCellClick={onCellClick}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

string|({ column, summary }, computedProps) => string
default: undefined

Specifies a css className string for the footer cells.
Specifying a string will use that className to all cells/columns of the footer row.
In order to specify the footer cell className just for a specific column, or set the className dynamically based on certain conditions, use a function - which in turn should return a string.
When footerRow.cellClassName is used, it will replace this prop.
When a function is used, it is called like
footerCellClassName({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
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: (_, computedProps) => {
        return <div>Selected rows: <b>{computedProps.computedSelectedCount}</b></div>
      }
    },

    colspan: {
      name: (_, computedProps) => computedProps.visibleColumns.length
    }
  }
]

const footerCellClassName = ({ column }, computedProps) => {
  if (column.name !== 'name'){
    return ''
  }

  if (computedProps.computedSelectedCount) {
    return 'global-with-selected-rows'

  }

  return ''
}

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 footerCellClassName</h3>
      <p>Please select some rows</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        defaultGroupBy={['country']}
        columns={columns}
        footerCellClassName={footerCellClassName}
        dataSource={cities}
        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|({ column, summary }, computedProps) => Object
default: undefined

Specifies a style object for the footer cells.
Specifying an object will use that style object to all cells/columns of the footer row.
In order to specify the footer cell style just for a specific column, or set the style object dynamically based on certain conditions, use a function - which in turn should return a style object.
When footerRow.cellStyle is used, it will replace this prop.
When a function is used, it is called like
cellStyle({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
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: (_, computedProps) => {
        return <div>Selected rows: <b>{computedProps.computedSelectedCount}</b></div>
      }
    },

    colspan: {
      name: (_, computedProps) => computedProps.visibleColumns.length
    }
  }
]

const footerCellStyle = ({ column }, computedProps) => {
  if (column.name !== 'name'){
    return
  }

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

  if (computedProps.computedSelectedCount) {
    style.background = '#ff595e'
    style.color = '#2e3439'
  }

  return style
}

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 footerCellStyle</h3>
      <p>Please select some rows</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        defaultGroupBy={['country']}
        columns={columns}
        footerCellStyle={footerCellStyle}
        dataSource={cities}
        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 />

string|({ column, summary }, computedProps) => string
default: undefined

Specifies a string className for the corresponding footer cell.
Specifying a string will use that css className to all cells/columns of the footer row.
In order to specify the footer cell className just for a specific column, or set the className dynamically based on certain conditions, use a function - which in turn should return a css className.
When a function is used, it is called like
cellClassName({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
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>
    },
    cellClassName: 'global-footer-color-blue'
  },
  {
    render: {
      population: ({ summary }) => <div>Population max: {summary.max}</div>
    },
    cellClassName: 'global-footer-color-blue'
  },
  {
    render: {
      population: ({ summary }) => <div>Population average: {summary.avg}</div>
    }
  },

  {
    render: {
      population: ({ summary }) => <div>Countries count: {summary.count}</div>
    }
  },
  {
    render: {
      population: ({ summary }) => <div>Population sum: {summary.sum}</div>
    }
  },

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

    cellClassName: ({ column }, computedProps) => {
      if (column.name !== 'name'){
        return ''
      }

      if (computedProps.computedSelectedCount) {
        return 'global-with-selected-rows'
      }

      return ''
    }
  }
]

const summaryReducer = {
  initialValue: {
    min: Infinity,
    max: 0,
    avg: 0,
    count: 0,
    sum: 0
  },
  reducer: (accumulator, item) => {
    if (item.population) {
      return {
        min: Math.min(accumulator.min, item.population),
        max: Math.max(accumulator.max, item.population),
        count: accumulator.count + 1,
        sum: accumulator.sum + 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 cellClassName</h3>
      <p>Please select some rows</p>
      <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 />

Object|({ column, summary }, computedProps) => Object
default: undefined

Specifies a style object for the corresponding footer cell.
Specifying an object will use that style object to all cells/columns of the footer row.
In order to specify the footer cell style just for a specific column, or set the style object dynamically based on certain conditions, use a function - which in turn should return a style object.
When a function is used, it is called like
cellStyle({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
Overrides footerCellStyle.
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>
    },
    cellStyle: {
      color: '#7986cb'
    }
  },
  {
    render: {
      population: ({ summary }) => <div>Population max: {summary.max}</div>
    },
    cellStyle: {
      color: '#7986cb'
    }
  },
  {
    render: {
      population: ({ summary }) => <div>Population average: {summary.avg}</div>
    }
  },

  {
    render: {
      population: ({ summary }) => <div>Countries count: {summary.count}</div>
    }
  },
  {
    render: {
      population: ({ summary }) => <div>Population sum: {summary.sum}</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 = '#ff595e'
        style.color = '#2e3439'
      }

      return style
    }
  }
]

const summaryReducer = {
  initialValue: {
    min: Infinity,
    max: 0,
    avg: 0,
    count: 0,
    sum: 0
  },
  reducer: (accumulator, item) => {
    if (item.population) {
      return {
        min: Math.min(accumulator.min, item.population),
        max: Math.max(accumulator.max, item.population),
        count: accumulator.count + 1,
        sum: accumulator.sum + 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 cellStyle</h3>
      <p>Please select some rows</p>
      <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 />

String
default: undefined

Specifies a CSS className for a group header. Applied to the wrapper container that also contains the cell headers.
For only applying a className to the group header, see groups.headerClassName
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', minWidth: 50 },
  { name: 'firstName', header: 'First Name', group: 'personalInfo', defaultFlex: 2 },
  { name: 'age', header: 'Age', group: 'personalInfo', type: 'number', minWidth: 50 },
  { name: 'email', header: 'Email', group: 'contactInfo', defaultFlex: 2 },
  { name: 'phone', header: 'Phone', group: 'contactInfo', defaultFlex: 1 },
  { name: 'city', header: 'City', group: 'location', defaultFlex: 1 },
  { name: 'streetName', header: 'Street name', group: 'street', defaultFlex: 1 },
  { name: 'streetNo', header: 'Street no', group: 'street', type: 'number', minWidth: 50 }
]

const groups = [
  { name: 'street', group: 'location', className: 'global-group-color-tomato', header: 'Street' },
  { name: 'personalInfo', header: 'Information about you', className: 'global-group-color-tomato' },
  { name: 'contactInfo', header: <span>Contact</span>, className: 'global-group-color-tomato' },
  { name: 'location', header: <span style={{ color: '#7986cb' }}>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>

String
default: undefined

Specifies a CSS className for a group header content. Applied only to the header element.
For only applying a className to the group header container, see groups.className
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', minWidth: 50 },
  { name: 'firstName', header: 'First Name', group: 'personalInfo', defaultFlex: 2 },
  { name: 'age', header: 'Age', group: 'personalInfo', type: 'number', minWidth: 50 },
  { name: 'email', header: 'Email', group: 'contactInfo', defaultFlex: 2 },
  { name: 'phone', header: 'Phone', group: 'contactInfo', defaultFlex: 1 },
  { name: 'city', header: 'City', group: 'location', defaultFlex: 1 },
  { name: 'streetName', header: 'Street name', group: 'street', defaultFlex: 1 },
  { name: 'streetNo', header: 'Street no', group: 'street', type: 'number', minWidth: 50 }
]

const groupClassName = 'global-group-color-tomato'

const groups = [
  { name: 'street', group: 'location', headerClassName: groupClassName, header: 'Street' },
  { name: 'personalInfo', header: 'Information about you', headerClassName: groupClassName },
  { name: 'contactInfo', header: <span>Contact</span>, headerClassName: groupClassName },
  { name: 'location', header: <span style={{ color: '#7986cb' }}>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>

string
default: undefined

Specifies a custom className to the group header.
import React from 'react'

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

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 50 },
  { name: 'firstName', header: 'First Name', group: 'personalInfo', defaultFlex: 2 },
  { name: 'age', header: 'Age', width: 100, group: 'personalInfo', type: 'number' },
  { name: 'email', header: 'Email', group: 'contactInfo', defaultFlex: 2 },
  { name: 'phone', header: 'Phone', group: 'contactInfo' },
  { name: 'city', header: 'City', group: 'location' },
  { name: 'streetName', header: 'Street name', minWidth: 150, group: 'street', defaultFlex: 1 },
  { name: 'streetNo', header: 'Street no', group: 'street', type: 'number' }
]
const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', header: 'Personal info', headerProps: { className: 'global-row-color-tomato' } },
  { name: 'contactInfo', header: 'Contact info', headerProps: { className: 'global-row-color-blue' } },
  { name: 'location', header: 'Location', headerProps: { className: 'global-row-color-red' } },
]

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: 550 }

export default () => <div>
  <h3>DataGrid with custom className on group header</h3>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>

Object
default: undefined

Specifies a custom style to the group header.
import React from 'react'

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

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 50 },
  { name: 'firstName', header: 'First Name', group: 'personalInfo', defaultFlex: 2 },
  { name: 'age', header: 'Age', width: 100, group: 'personalInfo', type: 'number' },
  { name: 'email', header: 'Email', group: 'contactInfo', defaultFlex: 2 },
  { name: 'phone', header: 'Phone', group: 'contactInfo' },
  { name: 'city', header: 'City', group: 'location' },
  { name: 'streetName', header: 'Street name', minWidth: 150, group: 'street', defaultFlex: 1 },
  { name: 'streetNo', header: 'Street no', group: 'street', type: 'number' }
]
const groups = [
  { name: 'street', group: 'location', header: 'Street' },
  { name: 'personalInfo', header: 'Personal info', headerProps: { style: { color: '#ef9a9a' } } },
  { name: 'contactInfo', header: 'Contact info', headerProps: { style: { color: '#7986cb' } } },
  { name: 'location', header: 'Location', headerProps: { style: { color: '#ff595e' } } },
]

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: 550 }

export default () => <div>
  <h3>DataGrid with custom style on group header</h3>
  <ReactDataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>

Object
default: undefined

Specifies a style object for a group header content. Applied only to the header element.
For only applying a style to the group header container, see groups.style
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', minWidth: 50 },
  { name: 'firstName', header: 'First Name', group: 'personalInfo', defaultFlex: 2 },
  { name: 'age', header: 'Age', group: 'personalInfo', type: 'number', minWidth: 50 },
  { name: 'email', header: 'Email', group: 'contactInfo', defaultFlex: 2 },
  { name: 'phone', header: 'Phone', group: 'contactInfo', defaultFlex: 1 },
  { name: 'city', header: 'City', group: 'location', defaultFlex: 1 },
  { name: 'streetName', header: 'Street name', group: 'street', defaultFlex: 1 },
  { name: 'streetNo', header: 'Street no', group: 'street', type: 'number', minWidth: 50 }
]

const groupStyle = {
  color: '#7986cb',
  fontStyle: 'italic'
}

const groups = [
  { name: 'street', group: 'location', headerStyle: groupStyle, header: 'Street' },
  { name: 'personalInfo', header: 'Information about you', headerStyle: groupStyle },
  { name: 'contactInfo', header: <span>Contact</span>, headerStyle: groupStyle },
  { name: 'location', header: <span style={{ color: '#ff595e' }}>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>

Object
default: undefined

Specifies a style object for a group header. Applied to the wrapper container that also contains the cell headers.
For only applying a style to the group header, see groups.headerStyle
import React from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', minWidth: 50 },
  { name: 'firstName', header: 'First Name', group: 'personalInfo', defaultFlex: 2 },
  { name: 'age', header: 'Age', group: 'personalInfo', type: 'number', minWidth: 50 },
  { name: 'email', header: 'Email', group: 'contactInfo', defaultFlex: 2 },
  { name: 'phone', header: 'Phone', group: 'contactInfo', defaultFlex: 1 },
  { name: 'city', header: 'City', group: 'location', defaultFlex: 1 },
  { name: 'streetName', header: 'Street name', group: 'street', defaultFlex: 1 },
  { name: 'streetNo', header: 'Street no', group: 'street', type: 'number', minWidth: 50 }
]

const groupStyle = {
  color: '#ef9a9a',
  fontStyle: 'italic'
}

const groups = [
  { name: 'street', group: 'location', style: groupStyle, header: 'Street' },
  { name: 'personalInfo', header: 'Information about you', style: groupStyle },
  { name: 'contactInfo', header: <span>Contact</span>, style: groupStyle },
  { name: 'location', header: <span style={{ color: '#7986cb' }}>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>

Number
default: undefined

If specified, the column headers will have this exact height.
Also see headerProps.
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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    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}
        headerHeight={100}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

string|({ column, summary }, computedProps) => string
default: undefined

Specifies a css className string for the locked rows cells.
Specifying a string will use that className to all cells/columns of the locked row.
In order to specify the footer cell className just for a specific column, or set the className dynamically based on certain conditions, use a function - which in turn should return a string.
When lockedRow.cellClassName is used, it will replace this prop.
When a function is used, it is called like
lockedRowCellClassName({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
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: (_, computedProps) => {
        return <div>Selected rows: <b>{computedProps.computedSelectedCount}</b></div>
      }
    },

    colspan: {
      name: (_, computedProps) => computedProps.visibleColumns.length
    }
  }
]

const lockedRowCellClassName = ({ column }, computedProps) => {
  if (column.name !== 'name'){
    return ''
  }

  if (computedProps.computedSelectedCount) {
    return 'global-with-selected-rows'

  }

  return ''
}

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 lockedRowCellClassName</h3>
      <p>Please select some rows</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        defaultGroupBy={['country']}
        columns={columns}
        lockedRowCellClassName={lockedRowCellClassName}
        dataSource={cities}
        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 />

Object|({ column, summary }, computedProps) => Object
default: undefined

Specifies a style object for the locked row cells.
Specifying an object will use that style object to all cells/columns of the locked row.
In order to specify the locked row cell style just for a specific column, or set the style object dynamically based on certain conditions, use a function - which in turn should return a style object.
When lockedRow.cellStyle is used, it will replace this prop.
When a function is used, it is called like
cellStyle({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
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: (_, computedProps) => {
        return <div>Selected rows: <b>{computedProps.computedSelectedCount}</b></div>
      }
    },

    colspan: {
      name: (_, computedProps) => computedProps.visibleColumns.length
    }
  }
]

const lockedRowCellStyle = ({ column }, computedProps) => {
  if (column.name !== 'name'){
    return
  }

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

  if (computedProps.computedSelectedCount) {
    style.background = '#ff595e'
    style.color = '#2e3439'
  }

  return style
}

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 row with custom lockedRowCellStyle</h3>
      <p>Please select some rows</p>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        defaultGroupBy={['country']}
        columns={columns}
        lockedRowCellStyle={lockedRowCellStyle}
        dataSource={cities}
        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 />

string|({ column, summary }, computedProps) => string
default: undefined

Specifies a string className for the corresponding locked row cell.
Specifying a string will use that css className to all cells/columns of the locked row.
In order to specify the locked row cell className just for a specific column, or set the className dynamically based on certain conditions, use a function - which in turn should return a css className.
When a function is used, it is called like
cellClassName({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
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>
    },
    cellClassName: 'global-footer-color-blue'
  },
  {
    position: 'start',
    render: {
      population: ({ summary }) => <div>Population max: {summary.max}</div>
    },
    cellClassName: 'global-footer-color-blue'
  },
  {
    position: 'start',
    render: {
      population: ({ summary }) => <div>Population average: {summary.avg}</div>
    }
  },

  {
    position: 'end',
    render: {
      population: ({ summary }) => <div>Countries count: {summary.count}</div>
    }
  },
  {
    position: 'end',
    render: {
      population: ({ summary }) => <div>Population sum: {summary.sum}</div>
    }
  },

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

    cellClassName: ({ column }, computedProps) => {
      if (column.name !== 'name'){
        return ''
      }

      if (computedProps.computedSelectedCount) {
        return 'global-with-selected-rows'
      }

      return ''
    }
  }
]

const summaryReducer = {
  initialValue: {
    min: Infinity,
    max: 0,
    avg: 0,
    count: 0,
    sum: 0
  },
  reducer: (accumulator, item) => {
    if (item.population) {
      return {
        min: Math.min(accumulator.min, item.population),
        max: Math.max(accumulator.max, item.population),
        count: accumulator.count + 1,
        sum: accumulator.sum + 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 cellClassName</h3>
      <p>Please select some rows</p>
      <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 />

Object|({ column, summary }, computedProps) => Object
default: undefined

Specifies a style object for the corresponding locked row cell.
Specifying an object will use that style object to all cells/columns of the footer row.
In order to specify the locked row cell style just for a specific column, or set the style object dynamically based on certain conditions, use a function - which in turn should return a style object.
When a function is used, it is called like
cellStyle({
  row,
  rowIndex,
  column,
  columnIndex,
  summary
}, computedProps)
so you have access to the current column, and other additional props.
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>
    },
    cellStyle: {
      color: '#7986cb'
    }
  },
  {
    position: 'start',
    render: {
      population: ({ summary }) => <div>Population max: {summary.max}</div>
    },
    cellStyle: {
      color: '#7986cb'
    }
  },
  {
    position: 'start',
    render: {
      population: ({ summary }) => <div>Population average: {summary.avg}</div>
    }
  },

  {
    position: 'end',
    render: {
      population: ({ summary }) => <div>Countries count: {summary.count}</div>
    }
  },
  {
    render: {
      population: ({ summary }) => <div>Population sum: {summary.sum}</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 = '#ff595e'
        style.color = '#2e3439'
      }

      return style
    }
  }
]

const summaryReducer = {
  initialValue: {
    min: Infinity,
    max: 0,
    avg: 0,
    count: 0,
    sum: 0
  },
  reducer: (accumulator, item) => {
    if (item.population) {
      return {
        min: Math.min(accumulator.min, item.population),
        max: Math.max(accumulator.max, item.population),
        count: accumulator.count + 1,
        sum: accumulator.sum + 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 cellStyle</h3>
      <p>Please select some rows</p>
      <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 />

String|Fn({ data, props, className })
default: undefined

A className for <ReactDataGrid /> rows. It can be a string or a function. In case it's specified as a function, it's called like rowClassName({ data, props, className }). The returned value is appended to the already existing className value of the row.
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 rowClassName = ({ data }) => {
  const colorMap = {
    ca: 'red',
    uk: 'blue'
  }

  return 'global-row-color-' + colorMap[data.country]
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    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}
        rowClassName={rowClassName}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object|Function(defaultStyle, rowDetails)
default: undefined

Can be used to customize the styling of the wrapper div where the row details are render via therenderRowDetails prop.
In case an object is provided, it will be merged with the default applied styles.
When a function is specified, the first param will be the default styles being applied, while the second param is the same object that is sent to renderRowDetails render prop. This function can either modify the style object it receives (in this case, it has to return undefined) or it can return a new style object.
NOTE: Make sure you know what you're doing - especially changing element heights can break the grid layout - use with caution.
See related rowDetailsWidth.
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 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 rowDetailsStyle = (style, { data }) => {
  // you have access to data, etc - see renderRowDetails param
  style.background = 'rgba(121,134,203,0.2)'
}

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

const App = () => {
  return (
    <ReactDataGrid
      idProperty="id"
      defaultExpandedRows={defaultExpandedRows}
      renderRowDetails={renderRowDetails}
      rowDetailsStyle={rowDetailsStyle}
      style={gridStyle}
      rowExpandHeight={400}
      columns={columns}
      dataSource={people}
    />
  );
}

export default () => <App />

String
default: undefined

Specifies a CSS class string for row focus.
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: 400 }

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' },
  { name: 'country', defaultFlex: 1,
    header: 'Country',
    render: ({ value })=> flags[value] ? flags[value] : value
  },
];

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

const App = () => {
  const [allowRowTabNavigation, setAllowRowTabNavigation] = useState(true);

  return (
    <div>
      <p>Navigate with Tab key</p>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={allowRowTabNavigation}
          onChange={setAllowRowTabNavigation}
        >
          Row Tab Navigation
        </CheckBox>
      </div>

      <TextInput style={{ marginBottom: 20, padding: 5, width: 250 }} type="text" autoFocus placeholder="Hit tab to navigate to grid" />
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        defaultFilterValue={filterValue}
        allowRowTabNavigation={allowRowTabNavigation}
        rowFocusClassName="global-row-background-tomato"
      />
      <TextInput style={{ marginTop: 20, padding: 5, width: 250 }} type="text" defaultValue="Hit shift+tab to navigate to grid" />
    </div>
  );
}

export default () => <App />

Object
default: undefined

A style object for row reorder drop position arrow.
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: 250 }

const rowReorderArrowStyle={
  background: 'green',
  height: 8,
  borderRadius: 1,
};

const columns = [
  { name: 'id', header: 'Id', defaultWidth: 60 },
  { name: 'name', header: 'Name', defaultWidth: 120 },
  {
    name: 'country',
    header: 'Country',
    defaultWidth: 120,
    render: ({ value }) => (flags[value] ? flags[value] : value),
  },
  { name: 'age', header: 'Age', type: 'number', defaultWidth: 120 },
];

const App = () => {
  return (
    <div>
      <h3>Grid with custom row reorder drop position arrow</h3>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        rowReorderColumn
        columns={columns}
        dataSource={[].concat(people)}
        rowReorderArrowStyle={rowReorderArrowStyle}
      />
    </div>
  );
}

export default () => <App />

Object|Fn({ data, props, style })
default: undefined

A style object to be applied to <ReactDataGrid /> rows. In case it's specified as a function, it's called like rowStyle({ data, props, style }). The returned object is merged on the already existing row style object.
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 rowStyle = ({ data }) => {
  const colorMap = {
    ca: '#7986cb',
    uk: '#ef9a9a'
  }

  return {
    color: colorMap[data.country]
  }
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    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}
        rowStyle={rowStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool|String
default: true

Controls which cell borders are displayed.
The DataGrid supports four strategies for displaying cell borders:
In the example below, you can see an example of showCellBorders.
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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [verticalBorders, setVerticalBorders] = useState(true)
  const [horizontalBorders, setHorizontalBorders] = useState(true)

  let showCellBorders = false
  if (verticalBorders) {
    showCellBorders = 'vertical'
  }
  if (horizontalBorders) {
    showCellBorders = 'horizontal'
  }
  if (horizontalBorders && verticalBorders) {
    showCellBorders = true
  }

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={verticalBorders}
          onChange={setVerticalBorders}
        >
          Show vertical borders
        </CheckBox>
      </div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={horizontalBorders}
          onChange={setHorizontalBorders}
        >
          Show horizontal borders
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        showCellBorders={showCellBorders}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Bool
default: false

Controls whether the <ReactDataGrid /> should fill the remaining vertical space (if any) available in its viewport with empty rows, when the current dataset does not have enough rows to fill the <ReactDataGrid /> height.
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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const dataSource = people.slice(0, 4)

const App = () => {
  const [showEmptyRows, setShowEmptyRows] = useState(true)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={showEmptyRows}
          onChange={setShowEmptyRows}
        >
          Show empty rows.
        </CheckBox>
      </div>

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

export default () => <App />

Bool
default: true

When true, applies some additional styling to rows on mouseover, to give nice feedback to the user.
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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [showHoverRows, setShowHoverRows] = useState(true)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={showHoverRows}
          onChange={setShowHoverRows}
        >
          Show hover effect for rows
        </CheckBox>
      </div>

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

export default () => <App />

Bool
default: true

Controls whether to show odd/even (zebra) styled rows.
Odd rows have the InovuaReactDataGrid__row--odd className applied.
Even rows have the InovuaReactDataGrid__row--even className applied. When showZebraRows=false, all the <ReactDataGrid /> rows have InovuaReactDataGrid__row--even applied.
Also see showEmptyRows.
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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [showZebraRows, setShowZebraRows] = useState(true)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={showZebraRows}
          onChange={setShowZebraRows}
        >
          Show zebra rows
        </CheckBox>
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        showZebraRows={showZebraRows}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Object
default: undefined

A style object to be applied to 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: 400,
  border: '1px solid #7986cb',
  boxShadow: '0 0 8px 2px rgba(121, 134,203, 0.5)'
}

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    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}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

String
default: "default-light"

The theme to be applied to the DataGrid - the default value is "default-light", however, the docs use "default-dark".
Here's a list of available thems:
  • "amber-light"
  • "amber-dark"
  • "blue-light"
  • "blue-dark"
  • "default-light"
  • "default-dark"
  • "green-light"
  • "green-dark"
  • "pink-light"
  • "pink-dark"
In order to use any of the above, you have to import @inovua/reactdatagrid-community/theme/<THEME_NAME>.css or @inovua/reactdatagrid-enterprise/theme/<THEME_NAME>.css. Also make sure you import @inovua/reactdatagrid-enterprise/base.css (or @inovua/reactdatagrid-community/base.css). The base.css file is included with @inovua/reactdatagrid-enterprise/index.css, which contains @inovua/reactdatagrid-enterprise/base.css AND the default theme, @inovua/reactdatagrid-enterprise/theme/default-light.css.
Themes for the DataGrid require quite a bit of styling - have a look at the default theme and at the Styling & theming page to see a list of the CSS classes used in the <ReactDataGrid />.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'
import ComboBox from '@inovua/reactdatagrid-community/packages/ComboBox'

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

const gridStyle = { minHeight: 550 }

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

const themeDataSource = [
  { id: 'default-dark', label: 'Dark theme' },
  { id: 'default-light', label: 'Light theme' }
]

const App = () => {
  const [theme, setTheme] = useState('default-dark')

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        Theme:{' '}
        <ComboBox
          style={{ width: 150}}
          inlineFlex
          collapseOnSelect
          clearIcon={false}
          searchable={false}
          changeValueOnNavigation
          dataSource={themeDataSource}
          value={theme}
          onChange={setTheme}
        />
      </div>
      <ReactDataGrid
        idProperty="id"
        style={gridStyle}
        theme={theme}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Methods

Fn()
undefined

When called, it programmatically blurs the <ReactDataGrid />.
See focus for an example.

Fn({columnId, rowIndex})
undefined

Cancels editing at the specified column and row.
Calling this method also triggers onEditCancel.
If no parameters are provided, it will cancel the currently edited cell.

Fn()
undefined

Clears any existing filters from the <ReactDataGrid />.
Using the column header menu, the user can also clear all grid filters.
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 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, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number', filterEditor: NumberFilter }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={()=> {
          gridRef.current.clearAllFilters()
        }}>
          Clear all filters
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        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 />

Fn(columnIdOrIndex)
undefined

Clears the filter for the specified column
The user can also clear the column filter by using the column header menu.
The argument passed to this method should be a column name (or id) or a column index (if an index is passed, it should be the index of the column in the currently visible columns array).
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 filterValue = [
  { name: 'name', operator: 'contains', type: 'string', value: 'o' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
]

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={()=> {
          gridRef.current.clearColumnFilter('name')
        }}>
          Clear name filter
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        defaultFilterValue={filterValue}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn()
undefined

Collapses all groups in the <ReactDataGrid />.
When called, it triggers onGroupCollapseChange
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: 600 }

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

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

  return (
    <div>
      <p>
        Collapsed groups: {JSON.stringify(Object.keys(collapsedGroups))}.
      </p>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => gridRef.current.collapseAllGroups()}>
          Collapse all
        </Button>
      </div>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => gridRef.current.expandAllGroups()}>
          Expand all
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        collapsedGroups={collapsedGroups}
        onGroupCollapseChange={setCollapsedGroups}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn()
undefined

Collapses all rows in the <ReactDataGrid /> (the <ReactDataGrid /> needs to be expandable, i.e., to have one of the following: enableRowExpand, expandedRows, defaultExpandedRows, renderRowDetails).
To expand all rows, see expandAllRows.
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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  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={() => {
          gridRef.current.expandAllRows()
        }} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => {
          gridRef.current.collapseAllRows()
        }}>
          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
        onReady={setGridRef}
        idProperty="id"
        expandedRows={expandedRows}
        collapsedRows={collapsedRows}
        onExpandedRowsChange={onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn()
undefined

Collapses all tree nodes in the <ReactDataGrid />.
When called, it triggers onExpandedNodesChange
import React, { useState, useCallback } from 'react'

import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import Button from '@inovua/reactdatagrid-community/packages/Button'
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', header: 'Name', defaultFlex: 1 },
  { name: 'size', header: 'Size', defaultWidth: 160 }
];

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

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

  return (
    <div>
      <h3>Collapse all tree nodes</h3>

      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => gridRef.current.collapseAllTreeNodes()}>
          Collapse all
        </Button>

        <Button style={{ marginLeft: 20 }} onClick={() => gridRef.current.expandAllTreeNodes()}>
          Expand all
        </Button>
      </div>

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

export default () => <App />

Fn({columnId, rowIndex, value})
undefined

Completes and confirms the editing at the specified column and row. Optionally you can pass the edit value, otherwise, the current edit value will be used.
Calling this method also triggers onEditComplete.
If no parameters are provided, it will complete (persist) the currently edited cell.

Fn()
undefined

Copies the active row to system clipboard.
In order to enable clipboard module, specify enableClipboard={true}
import React, { useCallback } 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,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps,
  { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copyActiveRowToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteActiveRowFromClipboard()
    },
  ];
};

const App = () => {
  const onCopyActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  const onPasteActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  return (
    <div>
      <h3>Select a row and then copy/paste from custom context menu</h3>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard
        onCopyActiveRowChange={onCopyActiveRowChange}
        onPasteActiveRowChange={onPasteActiveRowChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn()
undefined

Copy the selected cells to system clipboard.
In order to enable clipboard module, specify enableClipboard={true}
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: 550 };

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps,
  { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copySelectedCellsToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteSelectedCellsFromClipboard()
    },
  ];
};

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

  const onCopySelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  const onPasteSelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  return (
    <div>
      <h3>Copy/paste from custom context menu the selected cells</h3>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        enableClipboard
        onCopySelectedCellsChange={onCopySelectedCellsChange}
        onPasteSelectedCellsChange={onPasteSelectedCellsChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn()
undefined

Copies selected rows to system clipboard.
In order to enable clipboard module, specify enableClipboard={true}
For copy-paste multiple rows you need to enable checkboxColumn or enableSelection with multiSelect set to true.
import React, { useCallback, 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,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps, { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copySelectedRowsToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteSelectedRowsFromClipboard()
    },
  ];
};

const App = () => {
  const [checkboxColumn, setCheckboxColumn] = useState(true);
  const onCopySelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  const onPasteSelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  return (
    <div>
      <h3>Select some rows and then copy/paste from custom context menu</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={checkboxColumn} onChange={setCheckboxColumn}>Checkbox column</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard
        onCopySelectedRowsChange={onCopySelectedRowsChange}
        onPasteSelectedRowsChange={onPasteSelectedRowsChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
        checkboxColumn={checkboxColumn}
      />
    </div>
  );
};

export default () => <App />;

Fn()
undefined

Calling this deselects all records in the <ReactDataGrid />.
See selected, unselected and onSelectionChange for more examples and related props.
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: 400, marginTop: 10 }

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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, groupBy: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'First Name', groupBy: false, defaultFlex: 1 },
  { name: 'lastName', header: 'Last Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', groupBy: false, defaultFlex: 1 }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [unselected, setUnselected] = useState(null)
  const [selected, setSelected] = useState({ 1: true, 3: true })

  const dataSource = useCallback(loadData, [])

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

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => gridRef.current.selectAll()}>
          Select all
        </Button>

        <Button style={{ marginLeft: 8 }} onClick={() => gridRef.current.deselectAll()}>
          Deselect all
        </Button>
      </div>
      <div style={{marginBottom: 20}}>
        Unselected rows: {unselected && Object.keys(unselected).length ? JSON.stringify(Object.keys(unselected)) : (selected === true ? 'none' : 'too many')}.
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        columns={columns}
        checkboxOnlyRowSelect={true}
        pagination
        selected={selected}
        unselected={unselected}
        onSelectionChange={onSelectionChange}
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(editProps: Object)
undefined

A method designed to update the data when editing a cell in TreeGrid mode.
import React, { useState, useCallback, useRef } 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: 160 },
];

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

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

  const gridRef = useRef(null);

  const onEditComplete = useCallback(
    editProps => {
      const editedTreeData = gridRef.current.editedTreeData(editProps);

      setDataSource(editedTreeData || []);
    },
    [dataSource]
  );

  return (
    <div>
      <h3>Basic TreeGrid</h3>

      <ReactDataGrid
        treeColumn="name"
        handle={(ref: any) => (gridRef.current = ref ? ref.current : null)}
        defaultExpandedNodes={defaultExpandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}
        editable
        onEditComplete={onEditComplete}
      />
    </div>
  );
};

export default () => <App />;

Fn()
undefined

Expands all groups in the <ReactDataGrid />.
When called, it triggers onGroupCollapseChange
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: 600 }

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

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

  return (
    <div>
      <p>
        Collapsed groups: {JSON.stringify(Object.keys(collapsedGroups))}.
      </p>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => gridRef.current.collapseAllGroups() }>
          Collapse all
        </Button>
      </div>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => gridRef.current.expandAllGroups() }>
          Expand all
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        collapsedGroups={collapsedGroups}
        onGroupCollapseChange={setCollapsedGroups}
        defaultGroupBy={groupBy}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn()
undefined

Expands all rows in the <ReactDataGrid /> (the <ReactDataGrid /> needs to be expandable, i.e., to have one of the following: enableRowExpand, expandedRows, defaultExpandedRows, renderRowDetails).
A <ReactDataGrid /> has all rows expanded, when expandedRows=true.
However, in case you need some of the rows to be collapsed, use collapsedRows.
When this is invoked, onExpandedRowsChange({ expandedRows: true }) prop 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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  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={() => {
          gridRef.current.expandAllRows()
        }} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => {
          gridRef.current.collapseAllRows()
        }}>
          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
        onReady={setGridRef}
        idProperty="id"
        expandedRows={expandedRows}
        collapsedRows={collapsedRows}
        onExpandedRowsChange={onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn()
undefined

Expands all tree nodes in the <ReactDataGrid />.
When called, it triggers onExpandedNodesChange
import React, { useState, useCallback } from 'react'

import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import Button from '@inovua/reactdatagrid-community/packages/Button'
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', header: 'Name', defaultFlex: 1 },
  { name: 'size', header: 'Size', defaultWidth: 160 }
];

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

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

  return (
    <div>
      <h3>Expand all tree nodes</h3>

      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => gridRef.current.collapseAllTreeNodes()}>
          Collapse all
        </Button>

        <Button style={{ marginLeft: 20 }} onClick={() => gridRef.current.expandAllTreeNodes()}>
          Expand all
        </Button>
      </div>

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

export default () => <App />

Fn()
undefined

When called, it programmatically focuses the <ReactDataGrid />.
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'
const gridStyle = { marginTop: 10, minHeight: 300 }

const dataSource = [
  { 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 }
]

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [focused, setFocused] = useState(false)

  const onFocus = useCallback((event) => {
    setFocused(true)
  }, [])

  const onBlur = useCallback((event) => {
    setFocused(false)
  }, [])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => gridRef.current.focus()}>Focus grid</Button>
      </div>
      <div style={{marginBottom: 20}}>
        The grid is {focused ? 'focused' : 'blurred'}.
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        enableKeyboardNavigation
        style={gridStyle}
        idProperty="id"
        onFocus={onFocus}
        onBlur={onBlur}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(idNameOrIndex)
Object

Retrieves the column specified by the given first argument. It can be an index (the column index in the visible <ReactDataGrid /> columns), or a column identifier - a column.id or a column.name.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'
import Button from '@inovua/reactdatagrid-community/packages/Button'

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

const gridStyle = { minHeight: 550 }

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeCell, setActiveCell] = useState([5, 2]) // [row, column]

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const column = gridRef.current.getColumnBy(activeCell[1])
          inovua.notification.first.addNotification({content: 'Column: ' + column.name})
        }}>
          Get column of current active cell
        </Button>
        <NotificationBoard id="first" />
      </div>
      <ReactDataGrid
        idProperty="id"
        activeCell={activeCell}
        onActiveCellChange={setActiveCell}
        style={gridStyle}
        columns={columns}
        dataSource={people}
        onReady={setGridRef}
      />
    </div>
  );
}

export default () => <App />

Fn(index)
Number

Returns the item at the specified index in the dataSource.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'
import Button from '@inovua/reactdatagrid-community/packages/Button'

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

const gridStyle = { minHeight: 300 }

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState(1)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          inovua.notification.first.addNotification({ content: 'Name at index 2:' + gridRef.current.getItemAt(2).name })
        }}>
          Show name of item at index 2
        </Button>
        <NotificationBoard id="first" />
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(fn)
Number

Returns the index of the first item in the dataSource that satisfies the given function. Returns -1 if no matching item found.
The specified function is called multiple times, with the first param being the current item from the dataSource.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'
import Button from '@inovua/reactdatagrid-community/packages/Button'

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

const gridStyle = { minHeight: 300 }

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState(1)

  const getMaryIndex = useCallback(() => {
    return gridRef.current.getItemIndexBy((item) => item.name === 'Mary')
  }, [gridRef])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          inovua.notification.first.addNotification({ content: 'Index for Mary:' + getMaryIndex() })
        }}>
          Show index of "Mary"
        </Button>
        <NotificationBoard id="first" />
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(index)
String|Number

Returns the id of the row at the specified index.
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 NumericInput from '@inovua/reactdatagrid-community/packages/NumericInput'
import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

const gridStyle = { minHeight: 300 }

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

const App = () => {
  const initialIndex = 1;

  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState(initialIndex);
  const [index, setIndex] = useState(initialIndex)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <NumericInput value={index} onChange={setIndex} />
        <Button style={{ marginLeft: 20 }} onClick={() => {
          gridRef.current.setActiveIndex(index);
        }}>Set active index</Button>
      </div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          inovua.notification.first.addNotification({ content: 'Active row id:' + gridRef.current.getRowId(activeIndex) })
        }}>
          Show id of the active row
        </Button>
        <NotificationBoard id="first" />
      </div>
      <p>You have to programmatically set the active index because it will become -1 at blur.</p>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        activeIndex={activeIndex}
        onActiveIndexChange={setActiveIndex}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn()
Bool

Returns whether the <ReactDataGrid /> is currently showing a load mask or not. See setLoading for an example of the setLoading method.

Fn(indexOrData)
undefined

Returns true if the row at the specified index is expanded. Instead of the index, you can also pass the data object corresponding to the row you want to check.
See related isRowExpandedById.
import React, { useState, useCallback, useRef } 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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState()
  const [activeRowId, setActiveRowId] = useState()
  const [activeRowExpanded, setActiveRowExpanded] = useState()

  const propsRef = useRef(null);
  propsRef.current = gridRef && gridRef.current;

  const onActiveIndexChange = useCallback((index) => {
    const item = propsRef.current.getItemAt(index);
    const rowId = propsRef.current.getItemId(item);

    setActiveIndex(index)
    setActiveRowId(rowId)
    setActiveRowExpanded(propsRef.current.isRowExpanded(item))
  }, [])

  const onExpandedRowsChange = useCallback(({ expandedRows }) => {
    if (expandedRows) {
      setActiveRowExpanded(!!expandedRows[activeRowId])
    }
  }, [activeRowId])

  return (
    <div>
      {activeIndex == null ? null : <p>
        Active row: {activeIndex}. The row is {activeRowExpanded ? 'expanded': 'collapsed'}.
      </p>}
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        activeIndex={activeIndex}
        onActiveIndexChange={onActiveIndexChange}
        onExpandedRowsChange={onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(rowId)
undefined

Returns true if the row with the specified id is expanded
See related isRowExpanded.
import React, { useState, useCallback, useRef } 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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState()
  const [activeRowId, setActiveRowId] = useState()
  const [activeRowExpanded, setActiveRowExpanded] = useState()

  const propsRef = useRef(null);
  propsRef.current = gridRef && gridRef.current;

  const onActiveIndexChange = useCallback((index) => {
    const rowId = propsRef.current.getItemId(propsRef.current.getItemAt(index))

    setActiveIndex(index)
    setActiveRowId(rowId)
    setActiveRowExpanded(propsRef.current.isRowExpandedById(rowId))
  }, [])

  const onExpandedRowsChange = useCallback(({ expandedRows }) => {
    const newActiveRow = expandedRows ? !!expandedRows[activeRowId] : -1;

    setActiveRowExpanded(newActiveRow)
  }, [activeRowId])

  return (
    <div>
      {activeIndex == null ? null : <p>
        Active row: {activeIndex}. The row is {activeRowExpanded ? 'expanded': 'collapsed'}.
      </p>}
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        activeIndex={activeIndex}
        onActiveIndexChange={onActiveIndexChange}
        onExpandedRowsChange={onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(index: number) => boolean
undefined

Returns true if the row at the specified index is fully visible (is completely in the grid viewport), false otherwise.
import React, { useState } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

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

const gridStyle = { minHeight: 350 }

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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)

  return (
    <div>
      <p>
        <Button onClick={()=> {
          const visible = gridRef.current.isRowFullyVisible(1)
          inovua.notification.first.addNotification({
            title: 'Row 1 is ' + (visible ? 'fully visible': 'not fully visible')
          })
        }}>Row 1 fully visible?</Button>
      </p>

      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        dataSource={people}
        activeIndex={1}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
      />
      <NotificationBoard id="first" />
    </div>
  );
}

export default () => <App />

Fn()
undefined

Paste the active row from system clipboard.
In order to enable clipboard module, specify enableClipboard={true}
import React, { useCallback } 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,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps,
  { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copyActiveRowToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteActiveRowFromClipboard()
    },
  ];
};

const App = () => {
  const onCopyActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  const onPasteActiveRowChange = useCallback(row => {
    console.log(row);
  }, []);

  return (
    <div>
      <h3>Select a row and then copy/paste from custom context menu</h3>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard
        onCopyActiveRowChange={onCopyActiveRowChange}
        onPasteActiveRowChange={onPasteActiveRowChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn()
undefined

Paste the selected cells from system clipboard.
In order to enable clipboard module, specify enableClipboard={true}
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: 550 };

const columns = [
  {
    name: 'id',
    header: 'Id',
    defaultVisible: false,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps,
  { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copySelectedCellsToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteSelectedCellsFromClipboard()
    },
  ];
};

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

  const onCopySelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  const onPasteSelectedCellsChange = useCallback(cells => {
    console.log(cells);
  }, []);

  return (
    <div>
      <h3>Copy/paste from custom context menu the selected cells</h3>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        enableClipboard
        onCopySelectedCellsChange={onCopySelectedCellsChange}
        onPasteSelectedCellsChange={onPasteSelectedCellsChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
};

export default () => <App />;

Fn()
undefined

Paste the selected rows from system clipboard.
In order to enable clipboard module, specify enableClipboard={true}
For copy-paste multiple rows you need to enable checkboxColumn or enableSelection with multiSelect set to true.
import React, { useCallback, 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,
    minWidth: 300,
    type: 'number',
  },
  {
    name: 'name',
    header: 'Name',
    defaultFlex: 1,
    minWidth: 250,
  },
  {
    name: 'country',
    header: 'Country',
    defaultFlex: 1,
    minWidth: 100,
    defaultVisible: false,
  },
  { name: 'city', header: 'City', defaultFlex: 1, minWidth: 300 },
  { name: 'age', header: 'Age', minWidth: 150, type: 'number' },
  { name: 'email', header: 'Email', defaultFlex: 1, minWidth: 150 },
  {
    name: 'student',
    header: 'Student',
    defaultFlex: 1,
    render: ({ value }) => (value === true ? 'Yes' : 'No'),
  },
];

const renderClipboardContextMenu = (
  menuProps, { computedProps }
) => {
  if (!computedProps) {
    return;
  }

  menuProps.autoDismiss = true;
  menuProps.items = [
    {
      label: 'Copy to clipboard',
      onClick: () => computedProps.copySelectedRowsToClipboard()
    },
    {
      label: 'Paste from clipboard',
      onClick: () => computedProps.pasteSelectedRowsFromClipboard()
    },
  ];
};

const App = () => {
  const [checkboxColumn, setCheckboxColumn] = useState(true);
  const onCopySelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  const onPasteSelectedRowsChange = useCallback(rows => {
    console.log(rows);
  }, []);

  return (
    <div>
      <h3>Select some rows and then copy/paste from custom context menu</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={checkboxColumn} onChange={setCheckboxColumn}>Checkbox column</CheckBox>
      </div>

      <ReactDataGrid
        idProperty="id"
        theme="default-dark"
        enableClipboard
        onCopySelectedRowsChange={onCopySelectedRowsChange}
        onPasteSelectedRowsChange={onPasteSelectedRowsChange}
        renderRowContextMenu={renderClipboardContextMenu}
        style={gridStyle}
        columns={columns}
        dataSource={people}
        checkboxColumn={checkboxColumn}
      />
    </div>
  );
};

export default () => <App />;

Fn(Number)
undefined

Scrolls the <ReactDataGrid /> horizontally.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumericInput from '@inovua/reactdatagrid-community/packages/NumericInput'
import Button from '@inovua/reactdatagrid-community/packages/Button'
import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

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

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [value, setValue] = useState(300)

  const scrollToLeft = useCallback(() => {
    gridRef.current.setScrollLeft(value)
  }, [gridRef, value])

  const readScrollValue = useCallback(() => {
    inovua.notification.first.addNotification({
      title: 'Scroll left (getter)',
      content: 'Current scrolled value is: ' + gridRef.current.getScrollLeft() + ' px.'
    })
  }, [gridRef, value])

  return (
    <div>
      <div>
        Set how much to scroll:{' '}
        <NumericInput
          style={{ width: 80 }}
          minValue={1}
          value={value}
          step={10}
          onChange={setValue}
        />{' '}
        <Button
          style={{ height: 30, borderRadius: 3 }}
          onClick={scrollToLeft}
        >
          Scroll left
        </Button>{' '}
      </div>
      <p>
        When you press the getter button bellow, a notification will appear to show the scrolled value.
      </p>
      <div style={{marginBottom: 20}}>
        Get how much is scrolled:{' '}
        <Button
          style={{ height: 30, borderRadius: 3 }}
          onClick={readScrollValue}
        >
          Get scroll left number
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        sortable={false}
        dataSource={people}
      />
      <NotificationBoard id="first" />
    </div>
  );
}

export default () => <App />

Fn(index, {direction, force, duration, offset}, callback)
undefined

Programmatically scrolls horizontally to the visible column with the specified index. All parameters but the index are optional. When scrolling, it brings the specified column into view, if not already visible.
In the simplest scenario, call grid.scrollToColumn(5) to scroll to the sixth column (zero-based numbering).
For scrolling to a row at a specific index, use scrollToIndex.
For more details on programmatic scrolling, see Programmatic scrolling.
Additionally, you can pass other configuration options, like direction (either 'left' or 'right', (the default) , to bring the column to the left or right of the viewport), a duration for smooth scrolling (defaults to 100 milliseconds ) and force if you want to force the scrolling to happen even if the column is already visible in the viewport (defaults to false). Optionally, pass a callback - especially useful for being notified when smooth scrolling is finished.
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: 400, marginTop: 10 }

const columns = [
  { name: 'id', header: 'Id', defaultVisible: false, type: 'number', defaultWidth: 80 },
  { name: 'name', header: 'Name', defaultWidth: 200 },
  { name: 'city', header: 'City', defaultWidth: 200 },
  { name: 'country', header: 'Country', defaultFlex: 1, minWidth: 100,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'email', header: 'Email', defaultWidth: 200 },
  { name: 'age', header: 'Age', defaultWidth: 200, type: 'number' },
  { id: 'column_6', header: 'Col 6', defaultWidth: 200, render: () => 'column 6' },
  { id: 'column_7', header: 'Col 7', defaultWidth: 200, render: () => 'column 7' },
  { id: 'column_8', header: 'Col 8', defaultWidth: 200, render: () => 'column 8' },
  { id: 'column_9', header: 'Col 9', defaultWidth: 200, render: () => 'column 9' },
  { id: 'column_10', header: 'Col 10', defaultWidth: 200, render: () => 'column 10' },
  { id: 'column_11', header: 'Col 11', defaultWidth: 200, render: () => 'column 11' },
  { id: 'column_12', header: 'Col 12', defaultWidth: 200, render: () => 'column 12' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)

  const scrollTo = useCallback((index) => {
    return () => {
      gridRef.current.scrollToColumn(10, { duration: 300 })
    }
  }, [gridRef])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <Button onClick={scrollTo(10)}>
          Scroll to column 10 (duration: 300ms)
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        sortable={false}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(id, {direction, force, duration, offset}, callback)
undefined

Programmatically scroll to the row with the specified id. All parameters but the id are optional.
In the simplest scenario, call grid.scrollToId('f56') to scroll to the row with 'f56'
For scrolling to a row at a specific index, use scrollToIndex.
For more details on programmatic scrolling, see Programmatic scrolling.
Additionally, you can pass other configuration options, like direction (either 'top' or 'bottom', to bring the row to the top or bottom of the viewport), a duration for smooth scrolling (defaults to 100 milliseconds ) and force if you want to force the scrolling to happen even if the row is already visible in the viewport (defaults to false). Optionally, pass a callback - especially useful for being notified when smooth scrolling is finished.
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: 400, marginTop: 10 }

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 columns = [
  { name: 'id', header: 'Id', defaultVisible: true, groupBy: false, type: 'number', defaultWidth: 60 },
  { name: 'firstName', header: 'First Name', groupBy: false, defaultFlex: 1 },
  { name: 'lastName', header: 'Last Name', defaultFlex: 1 },
  {
    name: 'permissionToCall',
    header: 'Permission to call',
    flex: 1,
    render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
    renderGroupTitle: value => value === true || value === 'true' ? 'Calls allowed' : 'No calls allowed'
  }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const dataSource = useCallback(loadData, [])

  const scrollTo = useCallback((id) => {
    return () => {
      gridRef.current.scrollToId(id, { duration: 300 })
    }
  }, [gridRef])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <Button onClick={scrollTo(70)}>
          Scroll to id: 70 (duration: 300ms)
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        sortable={false}
        dataSource={dataSource}
        defaultLimit={100}
      />
    </div>
  );
}

export default () => <App />

Fn(index, {direction, force, duration, offset}, callback)
undefined

This method has the exact same API as scrollToId except that you pass an index instead of an id.
In the simplest scenario, call grid.scrollToIndex(56) to scroll to the row at index 56.
Additionally, you can pass other configuration options, like direction (either 'top' or 'bottom', to bring the row to the top or bottom of the viewport), a duration for smooth scrolling (defaults to 100 milliseconds ) and force if you want to force the scrolling to happen even if the row is already visible in the viewport (defaults to false). Optionally, pass a callback - especially useful for being notified when smooth scrolling is finished.
For more details on programmatic scrolling, see Programmatic scrolling.
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: 400, marginTop: 10 }

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 columns = [
  { name: 'id', hedaer: 'Id', defaultVisible: false, groupBy: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'First Name', groupBy: false, defaultFlex: 1 },
  { name: 'lastName', header: 'Last Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', groupBy: false, defaultFlex: 1 }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const dataSource = useCallback(loadData, [])

  const scrollTo = useCallback((index) => {
    return () => {
      gridRef.current.scrollToIndex(index, { duration: 300 })
    }
  }, [gridRef])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <Button
          onClick={scrollTo(70)}
        >
          Scroll to index: 70 (duration: 300ms)
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        sortable={false}
        dataSource={dataSource}
        defaultLimit={100}
      />
    </div>
  );
}

export default () => <App />

Fn(Number)
undefined

Scrolls the <ReactDataGrid /> vertically.
Although this is listed under the methods list, it should be used as a getter/setter for reading/setting the scroll position for the <ReactDataGrid />.
import React, { useState, useCallback } from 'react'
import ReactDataGrid from '@inovua/reactdatagrid-enterprise'
import '@inovua/reactdatagrid-enterprise/index.css'

import NumericInput from '@inovua/reactdatagrid-community/packages/NumericInput'
import Button from '@inovua/reactdatagrid-community/packages/Button'
import NotificationBoard from '@inovua/react-ui-toolkit/Notification'
import '@inovua/react-ui-toolkit/Notification/index.css'

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

const gridStyle = { height: 300, marginTop: 10 }

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [value, setValue] = useState(150)

  const scrollToTop = useCallback(() => {
    gridRef.current.scrollTop = value
  }, [gridRef, value])

  const readScrollValue = useCallback(() => {
    inovua.notification.first.addNotification({
      title: 'Scroll top (getter)',
      content: 'Current scrolled value is: ' + gridRef.current.scrollTop + ' px.'
    })
  }, [gridRef, value])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        Set how much to scroll:{' '}
        <NumericInput
          style={{ width: 80 }}
          minValue={1}
          step={10}
          value={value}
          onChange={setValue}
        />{' '}
        <Button
          style={{ height: 30, borderRadius: 3 }}
          onClick={() => scrollToTop()}
        >
          Scroll top (setter)
        </Button>{' '}
      </div>
      <p>
        When you press the getter button bellow, a notificatin will appear to show the scrolled value.
      </p>
      <div style={{marginBottom: 20}}>
        Get how much is scrolled:{' '}
        <Button
          style={{ height: 30, borderRadius: 3 }}
          onClick={() => readScrollValue()}
        >
          Scroll top (getter)
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        sortable={false}
        dataSource={people}
      />
      <NotificationBoard id="first" />
    </div>
  );
}

export default () => <App />

Fn()
undefined

Calling this selects all records in the <ReactDataGrid />.
See selected, unselected and onSelectionChange for more examples and related props.
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: 400, marginTop: 10 }

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 columns = [
  { name: 'id', header: 'Id', defaultVisible: false, groupBy: false, type: 'number', defaultWidth: 80 },
  { name: 'firstName', header: 'First Name', groupBy: false, defaultFlex: 1 },
  { name: 'lastName', header: 'Last Name', defaultFlex: 1 },
  { name: 'email', header: 'Email', groupBy: false, defaultFlex: 1 }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [unselected, setUnselected] = useState(null)
  const [selected, setSelected] = useState({ 1: true, 3: true })

  const dataSource = useCallback(loadData, [])

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

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => gridRef.current.selectAll()}>
          Select all
        </Button>

        <Button style={{ marginLeft: 8 }} onClick={() => gridRef.current.deselectAll()}>
          Deselect all
        </Button>
      </div>
      <div style={{marginBottom: 20}}>
        Unselected rows: {unselected && Object.keys(unselected).length ? JSON.stringify(Object.keys(unselected)) : (selected === true ? 'none' : 'too many')}.
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        columns={columns}
        checkboxOnlyRowSelect={true}
        pagination
        selected={selected}
        unselected={unselected}
        onSelectionChange={onSelectionChange}
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(columnIdOrIndex, value)
undefined

Sets the filter value for the specified column
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 filterValue = [
  { name: 'name', operator: 'startsWith', type: 'string', value: '' },
  { name: 'age', operator: 'gte', type: 'number', value: 21 }
]

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={()=> {
          gridRef.current.setColumnFilterValue('name', 'B')
        }}>
          Filter by names starting with 'B'
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        defaultFilterValue={filterValue}
        editable
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(columnId: String, skipHeader: Boolean)
undefined

It calculates the size of the column content of the given id, so that the full content is displayed.
The method can take two parameters, the first parameter is required, and the second one is optional:
  • columnId: String, which is the id of the column to be resized
  • and skipHeader: Boolean, which it is a flag. If skipHeader is true the algorithm will not include header width in computation, if it is false, will do so.
In order to setColumnSizeAuto to work, enableColumnAutosize should be true and the column should be resizable.
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';
import Button from '@inovua/reactdatagrid-community/packages/Button';

const gridStyle = { minHeight: 550 };

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

const App = () => {
  const [gridRef, setGridRef] = useState(null);

  return (
    <div>
      <h3>Grid with 'name' column to be autosized</h3>

      <div style={{ marginBottom: 20 }}>
        <Button
          onClick={() => {
            if (gridRef && gridRef.current.setColumnSizeAuto) {
              gridRef.current.setColumnSizeAuto('name');
            }
          }}
        >
          Set 'name' column size auto
        </Button>
      </div>

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

export default () => <App />;

Fn()
undefined

When called, it calculates the size of all resizable columns so that it fits the width of the grid.
In order to setColumnSizesToFit to work, enableColumnAutosize should be true and the column should be resizable.
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';
import Button from '@inovua/reactdatagrid-community/packages/Button';

const gridStyle = { minHeight: 550 };

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

const App = () => {
  const [gridRef, setGridRef] = useState(null);

  return (
    <div>
      <h3>Grid with column sizes to fit</h3>

      <div style={{ marginBottom: 20 }}>
        <Button
          onClick={() => {
            if (gridRef && gridRef.current.setColumnSizesToFit) {
              gridRef.current.setColumnSizesToFit();
            }
          }}
        >
          Set column sizes to fit
        </Button>
      </div>

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

export default () => <App />;

Fn({ columnIds: String[], skipHeader: Boolean, skipSortTool: Boolean })
undefined

It calculates the size of the content of all resizable columns, so that the full content is displayed.
The method can take three parameters, which are optional:
  • columnIds: String[], which is an array of strings with all the column ids that are to be resized
  • skipHeader: Boolean, which it is a flag. If skipHeader is true the algorithm will not include header width in computation, if it is false, will do so.
  • and skipSortTool: Boolean, which if is true it will skip the sort tool dimensions when calculating the width of the cells.
In order to setColumnsSizesAuto to work, enableColumnAutosize should be true and the column should be resizable.
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';
import Button from '@inovua/reactdatagrid-community/packages/Button';
import CheckBox from '@inovua/reactdatagrid-community/packages/CheckBox';

const gridStyle = { minHeight: 550 };

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

const App = () => {
  const [gridRef, setGridRef] = useState(null);
  const [skipSortTool, setSkipSortTool] = useState(false);

  const setColumnsSizesAuto = useCallback(
    (skipHeader, skipSortTool) => {
      if (gridRef && gridRef.current.setColumnsSizesAuto) {
        gridRef.current.setColumnsSizesAuto({
          skipHeader,
          skipSortTool
        });
      }
    },
    [gridRef]
  );

  return (
    <div>
      <h3>Grid with auto size</h3>

      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={skipSortTool} onChange={setSkipSortTool}>
          skipSortTool
        </CheckBox>
      </div>

      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => setColumnsSizesAuto(false, skipSortTool)}>
          Set column sizes auto
        </Button>
      </div>

      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => setColumnsSizesAuto(true, skipSortTool)}>
          Set column sizes auto (skipHeader)
        </Button>
      </div>

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

export default () => <App />;

Fn(index, item: Object, config: { replace: Bool })
undefined

Sets the properties of the item at the specified index in the dataSource. The second param is the item that will be merged onto the current item at the specified index. If config.replace is true, it will replace the specified items altogether (note that replacing the items, with a different one, that has another id value can have undesired effects).
UseclearDataSourceCacheOnChange to clear any cached values (as a result to calls to this method) when the dataSource changes.
You should not change the id value (see idProperty) for an item - since this can have undesired effects.
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: 300 }

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          gridRef.current.setItemAt(2, { name: 'Danny' })
        }}>
          Set name of item at index 2 to be "Danny"
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(index, propertyName: String, value: Any)
undefined

Sets the property of the item at the specified index in the dataSource.
You should not change the id value (see idProperty) for an item - since this can have undesired effects.
UseclearDataSourceCacheOnChange to clear any cached values (as a result to calls to this method) when the dataSource changes.
When using a tree (see treeColumn), you can use clearNodeCacheOnDataSourceChange to clear any cached values (as a result to calls to this method) when the dataSource changes.
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: 300 }

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState(1)

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          gridRef.current.setItemPropertyAt(2, 'name', 'Danny')
        }}>
          Set name of item at index 2 to be "Danny"
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(items: Array, config: { replace: Bool })
undefined

Sets the properties of an array of specified items in dataSource. If config.replace is true, it will replace the specified item altogether (note that replacing the item, with a different one, that has another id value can have undesired effects).
UseclearDataSourceCacheOnChange to clear any cached values (as a result to calls to this method) when the dataSource changes.
You should not change the id value (see idProperty) for an item - since this can have undesired effects.
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'

const gridStyle = { minHeight: 300 }

const colsString = 'abcdefghij'

const buildColumns = cols => {
  return cols.split('').map(letter => {
    return {
      defaultWidth: 120,
      header: letter.toUpperCase(),
      name: letter
    }
  }) 
}

const buildDataSource = (records, cols) => {
  const data = []
  for (let i = 0; i < records; i++) {
    const result = {
      id: i
    }

    cols.split('').map(letter => {
      result[letter] = letter.toUpperCase() + ' ' + (i + 1)
    })

    data.push(result)
  }

  return data
}

const getRandomInt = max => {
  return Math.floor(Math.random() * max)
}

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [columns, setColumns] = useState(buildColumns(colsString))
  const [dataSource, setDataSource] = useState(buildDataSource(100, colsString))

  const setItemsAt = () => {
    const startIndex = 0
    const endIndex = 100
    const sliceData = dataSource.slice(startIndex, endIndex)

    const items = sliceData.map((_, index) => {
      const row = {
        id: index
      }

      colsString.split('').map(letter => {
        const randomNumber = getRandomInt(endIndex)
        let color = '#9ba7b4'
        if (randomNumber > (2/3) * endIndex) color = '#8bb58d'
        if (randomNumber < endIndex / 3) color = '#e6a0a0'

        const property = letter
        const value = (
          <span>
            {letter.toUpperCase() + ' ' + (index + 1) + ' - '}
            <span style={{ color }}>{randomNumber}</span>
          </span>
        )

        row[property] = value
      })

      return row
    })

    gridRef.current.setItemsAt(items, {
      replace: false
    })
  }

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={setItemsAt}>
          Set value for all items
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(loading: Bool)
undefined

Makes the <ReactDataGrid /> show a loading mask.
If the controlled loading prop is used, calling this method will only trigger onLoadingChange, and you have to update the loading prop yourself.
In fact, when calling setLoading, onLoadingChange is called whether you're using controlled loading or the uncontrolled defaultLoading, or no loading prop at all. In case of uncontrolled or unspecified loading prop, the load mask is shown/hidden depending on the parameter you call setLoading with.
For async dataSource, the dataSource will trigger onLoadingChange when it starts loading and when it resolves, so you generally don't need to use setLoading yourself.
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'
const gridStyle = { marginTop: 10, minHeight: 400 }

const dataSource = [
  { 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 }
]

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [isLoadingKey, setIsLoadingKey] = useState(false)

  const isLoading = gridRef ? gridRef.current.isLoading() : false
  return (
    <div>
      <div key={isLoadingKey} style={{ marginBottom: 20 }}>
        Is loading: {isLoading ? 'true' : 'false'}
      </div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          gridRef.current.setLoading(true)
          setTimeout(() => setIsLoadingKey(true), 0)
        }}>
          Set loading to true
        </Button>

        <Button style={{ marginLeft: 8 }} onClick={() => {
          gridRef.current.setLoading(false)
          setTimeout(() => setIsLoadingKey(false), 0)
        }}>
          Set loading to false
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        style={gridStyle}
        idProperty="id"
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn(dataOrIndex, expanded)
undefined

Sets the expand state of the specified row. The row can be specified either by providing the row index or the data object corresponding to the row.
See related setRowExpandedById.
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 NumericInput from '@inovua/reactdatagrid-community/packages/NumericInput'

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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState();
  const [index, setIndex] = useState();

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <NumericInput value={index} onChange={setIndex} />
        <Button
          style={{ marginLeft: 20 }}
          onClick={() => {
            gridRef.current.setActiveIndex(index);
          }}
        >
          Set active index
        </Button>
      </div>
      <div style={{ marginBottom: 20}}>
        <Button
          style={{ marginRight: 20}}
          disabled={activeIndex === undefined}
          onClick={() => gridRef.current.setRowExpandedAt(activeIndex, true)}
        >
          Expand active row
        </Button>
        <Button
          style={{ marginRight: 20}}
          disabled={activeIndex === undefined}
          onClick={() => gridRef.current.setRowExpandedAt(activeIndex, false)}
        >
          Collapse active row
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        onActiveIndexChange={setActiveIndex}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(rowId, expanded)
undefined

Sets the expand state of the row with the specified id.
See related setRowExpanded.
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 NumericInput from '@inovua/reactdatagrid-community/packages/NumericInput'

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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null);
  const [activeIndex, setActiveIndex] = useState();
  const [index, setIndex] = useState();

  const onActiveIndexChange = useCallback((index) => {
    setActiveIndex(index)
  }, [])

  const toggleExpandedIndex = useCallback((expand) => {
    const id = gridRef.current.getItemId(gridRef.current.getItemAt(activeIndex));
    gridRef.current.setRowExpandedById(id, expand)
  }, [gridRef, activeIndex])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <NumericInput
          style={{ width: 100 }}
          value={index}
          onChange={setIndex}
        />
        <Button
          style={{ marginLeft: 20 }}
          onClick={() => {
            gridRef.current.setActiveIndex(index);
          }}
        >
          Set active index
        </Button>
      </div>
      <div style={{ marginBottom: 20}}>
        <Button
          style={{ marginRight: 20}}
          disabled={activeIndex === undefined}
          onClick={() => toggleExpandedIndex(true)}
        >
          Expand active row
        </Button>
        <Button
          style={{ marginRight: 20}}
          disabled={activeIndex === undefined}
          onClick={() => toggleExpandedIndex(false)}
        >
          Collapse active row
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        activeIndex={activeIndex}
        onActiveIndexChange={onActiveIndexChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(index: Number, selected: Bool)
undefined

Sets the selected state of the specified row.
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: 300 }

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

const App = () => {
  const [gridRef, setGridRef] = useState(null)
  const [activeIndex, setActiveIndex] = useState(1)

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => {
          const index = activeIndex
          const selected = gridRef.current.isRowSelected(index)

          gridRef.current.setRowSelected(index, !selected)
        }}>
          Toggle active row selection
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        checkboxColumn
        checkboxOnlyRowSelect
        activeIndex={activeIndex}
        onActiveIndexChange={setActiveIndex}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(scrollPos, {orientation, duration}, callback)
undefined

Programmatically smooth scroll to the specified scrollPos on the axis defined by orientation (either "horizontal" or "vertical" are accepted values). So grid.smoothScrollTo(120, { orientation: 'horizontal'}) sets scrollLeft to 120. duration defaults to 100 milliseconds.
For more details on programmatic scrolling, see Programmatic scrolling.
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: 400, marginTop: 10 }

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

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 [gridRef, setGridRef] = useState(null)
  const dataSource = useCallback(loadData, [])

  return (
    <div>
      <div style={{marginBottom: 20}}>
        <Button
          disabled={Array.isArray(dataSource)}
          onClick={() => {
            gridRef.current.smoothScrollTo(500, { orientation: 'vertical', duration: 500 })
          }}
        >
            Smooth scroll vertically to 500px (duration: 500ms)
        </Button>
      </div>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        style={gridStyle}
        columns={columns}
        sortable={false}
        dataSource={dataSource}
      />
    </div>
  );
}

export default () => <App />

Fn({columnId, rowIndex, value})
undefined

Starts inline edit at the specified column and row. Optionally, you can provide an initial value. If no value is specified, the value in the <ReactDataGrid /> cell will be used.
If the specified cell is not in the viewport, the <ReactDataGrid /> will scroll to show the editing cell in the 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 people from './people'
import flags from './flags'

const gridStyle = { minHeight: 550 }

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

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

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

    setDataSource(data)
  }, [dataSource])

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={()=> {
          gridRef.current.startEdit({ rowIndex: 2, columnId: 'name' })
        }}>
          Start edit row 2, column name
        </Button>
      </div>
      <ReactDataGrid
        idProperty="id"
        onReady={setGridRef}
        style={gridStyle}
        onEditComplete={onEditComplete}
        editable
        columns={columns}
        dataSource={dataSource}
      />
    </div>
  )
}

export default () => <App />

Fn(dataOrIndex)
undefined

Toggles the expand state of the specified row. The row can be specified either by providing the row index or the data object corresponding to the row.
See related toggleRowExpandById.
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 NumericInput from '@inovua/reactdatagrid-community/packages/NumericInput'

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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null);
  const [activeIndex, setActiveIndex] = useState();
  const [index, setIndex] = useState();

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <NumericInput
          style={{ width: 100 }}
          value={index}
          onChange={setIndex}
        />
        <Button
          style={{ marginLeft: 20 }}
          onClick={() => {
            gridRef.current.setActiveIndex(index);
          }}
        >
          Set active index
        </Button>
      </div>
      <Button
        style={{ marginBottom: 20}}
        disabled={activeIndex === undefined}
        onClick={() => gridRef.current.toggleRowExpand(activeIndex)}
      >
        Toggle expand for active row
      </Button>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        activeIndex={activeIndex}
        onActiveIndexChange={setActiveIndex}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />

Fn(rowId)
undefined

Toggles the expand state of the row with the specified id.
See related toggleRowExpand.
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 NumericInput from '@inovua/reactdatagrid-community/packages/NumericInput'

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', header: 'Id', defaultVisible: false, defaultWidth: 80, type: 'number' },
  { name: 'name', header: 'Name', defaultFlex: 1 },
  { name: 'country', header: 'County', defaultFlex: 1,
    render: ({ value }) => flags[value] ? flags[value] : value
  },
  { name: 'city', header: 'City', defaultFlex: 1 },
  { name: 'age', header: 'Age', defaultFlex: 1, type: 'number' }
]

const App = () => {
  const [gridRef, setGridRef] = useState(null);
  const [activeIndex, setActiveIndex] = useState();
  const [index, setIndex] = useState();

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <NumericInput
          style={{ width: 100 }}
          value={index}
          onChange={setIndex}
        />
        <Button
          style={{ marginLeft: 20 }}
          onClick={() => {
            gridRef.current.setActiveIndex(index);
          }}
        >
          Set active index
        </Button>
      </div>
      <Button
        style={{ marginBottom: 20 }}
        disabled={activeIndex === undefined}
        onClick={() => {
          const id = gridRef.current.getItemId(
            gridRef.current.getItemAt(activeIndex)
          );
          gridRef.current.toggleRowExpandById(id);
        }}
      >
        Toggle expand for active row
      </Button>
      <ReactDataGrid
        onReady={setGridRef}
        idProperty="id"
        activeIndex={activeIndex}
        onActiveIndexChange={setActiveIndex}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={columns}
        dataSource={people}
      />
    </div>
  );
}

export default () => <App />
Top