Top
DataGrid API - API
DataGrid API
Props (200)
Callback Props (41)
Styling Props (22)
Methods (36)
Below you can find a list of public props that the <DataGrid /> 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 <DataGrid /> active when the <DataGrid /> receives focus - see activeIndex.
When the <DataGrid /> receives focus and you hit the ArrowDown key, the first row is becomes active, even if activateRowOnFocus is false.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      activateRowOnFocus: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(activateRowOnFocus) => this.setState({ activateRowOnFocus }) }
          checked={this.state.activateRowOnFocus}>
          Activate row on focus
        </CheckBox>
      </div>

      <input style={{ marginBottom: 20, padding: 5, width: 250 }} type="text" autoFocus defaultValue="Hit tab to navigate to grid" />
      <DataGrid
        idProperty="id"
        style={gridStyle}
        activateRowOnFocus={this.state.activateRowOnFocus}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
      <input 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 <DataGrid /> (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<DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 300 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      enableKeyboardNavigation: true,
      activeCell: [4, 1],
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', minWidth: 100 },
        { name: 'age', minWidth: 80, type: 'number' }
      ],
      dataSource: people
    }

    this.onActiveCellChange = this.onActiveCellChange.bind(this)
  }

  onActiveCellChange(activeCell) {
    this.setState({
      activeCell
    })
  }

  render() {
    const { enableKeyboardNavigation, activeCell } = this.state
    return <div>
      <div>
        <CheckBox checked={enableKeyboardNavigation} onChange={(enableKeyboardNavigation) => this.setState({ enableKeyboardNavigation })}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <p>Currently active cell: {JSON.stringify(activeCell)}.</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        activeCell={activeCell}
        onActiveCellChange={this.onActiveCellChange}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> active cell so often. Therefore, the updates are throttled, at 100 milliseconds by default in order to keep the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 300 }

const defaultActiveCell = [4, 1]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', minWidth: 120 },
        { name: 'age', minWidth: 80, type: 'number' }
      ],
      dataSource: people
    }
  }

  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        activeCellThrottle={300}
        defaultActiveCell={defaultActiveCell}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> with keyboard navigation, as the active index is updated, the <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 300 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      enableKeyboardNavigation: true,
      activeIndex: 2,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', minWidth: 100, flex: 1 },
        { name: 'age', minWidth: 80, type: 'number' }
      ],
      dataSource: people
    }

    this.onActiveIndexChange = this.onActiveIndexChange.bind(this)
  }

  onActiveIndexChange(activeIndex) {
    this.setState({
      activeIndex
    })
  }

  render() {
    const { enableKeyboardNavigation, activeIndex } = this.state
    return <div>
      <div>
        <CheckBox checked={enableKeyboardNavigation} onChange={(enableKeyboardNavigation) => this.setState({ enableKeyboardNavigation })}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <p>Current active index: {activeIndex}.</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        activeIndex={activeIndex}
        onActiveIndexChange={this.onActiveIndexChange}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: 100
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 <DataGrid /> active cell so often. Therefore, the updates are throttled, at 100 milliseconds by default in order to keep the <DataGrid /> snappy & responsive.
The value specifies the number of milliseconds to throttle the update by.
For updating active cell, see the activeCellThrottle prop.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 300 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', minWidth: 120 },
        { name: 'age', minWidth: 80, type: 'number' }
      ],
      dataSource: people
    }
  }

  render() {
    const { activeIndex } = this.state
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        activeIndexThrottle={300}
        defaultActiveIndex={1}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80 },
  { name: 'firstName', group: 'personalInfo', flex: 2 },
  { name: 'age', group: 'personalInfo', type: 'number' },
  { name: 'email', group: 'contactInfo', flex: 2 },
  { name: 'phone', group: 'contactInfo' },
  { name: 'city', group: 'location' },
  { name: 'streetName', group: 'street', flex: 1 },
  { name: 'streetNo', group: 'street', type: 'number' }
]
const groups = [
  { name: 'street', group: 'location' },
  { name: 'personalInfo', group: 'details' },
  { name: 'contactInfo', group: 'details' },
  { name: 'location', group: 'details' },
  { name: 'details', header: 'Detailed info' }
]

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 }

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

    this.state = {
      allowGroupSplitOnReorder: false
    }
  }
  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        <p>Try dragging columns to break up some groups.</p>
        <CheckBox checked={this.state.allowGroupSplitOnReorder} onChange={(allowGroupSplitOnReorder) => {
          this.setState({ allowGroupSplitOnReorder })
        }}>
          Allow group split on reorder
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnMinWidth={100}
        columns={columns}
        groups={groups}
        allowGroupSplitOnReorder={this.state.allowGroupSplitOnReorder}
        dataSource={dataSource}
      />
    </div>
  }
}
export default () => <App />
Bool
default: false
Specifies if a third, unsorted state should be allowed within a single sort <DataGrid />, when toggling the sort.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      sortable: true,
      allowUnsort: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'firstName', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ],
      dataSource: people
    }
  }
  render() {
    const { sortable, allowUnsort } = this.state
    return <div>
      <div>
        <CheckBox
          checked={sortable}
          onChange={(sortable) => this.setState({ sortable })}
        >
          Sortable grid
        </CheckBox>
      </div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          disabled={!this.state.sortable}
          checked={allowUnsort}
          onChange={(allowUnsort) => this.setState({ allowUnsort })}
        >
          Allow unsorted state
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        sortable={sortable}
        allowUnsort={allowUnsort}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Array
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 array of strings - each string representing a cell. 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', resizable: false, sortable: false, header: 'ID - unsortable' },
        { name: 'name', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', defaultWidth: 100, type: 'number' }
      ],
      dataSource: people,
      cellSelection: ["2,name", "2,city"]
    }
    this.onCellSelectionChange = this.onCellSelectionChange.bind(this)
  }
  onCellSelectionChange(cellSelection) {
    this.setState({
      cellSelection
    })
  }
  render() {
    return <div>
      <p>
        Selected cells: {this.state.cellSelection.length == 0 ? 'none' : JSON.stringify(this.state.cellSelection)}.
      </p>
      <DataGrid
        idProperty="id"
        cellSelection={this.state.cellSelection}
        onCellSelectionChange={this.onCellSelectionChange}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool|Object
default: undefined
Specifying a truthy value, will show a checkbox column as the first column of the <DataGrid />. 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 <DataGrid /> 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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 60 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit, sortInfo }) => fetch(DATASET_URL+ '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo): '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      checkboxOnlyRowSelect: true
    }
  }

  render() {
    const { checkboxOnlyRowSelect } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={checkboxOnlyRowSelect}
          onChange={(checkboxOnlyRowSelect) => this.setState({ checkboxOnlyRowSelect })}
        >
          Update row select using checkbox clicks only
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        columns={this.state.columns}
        checkboxOnlyRowSelect={checkboxOnlyRowSelect}
        pagination
        defaultSelected={true}
        defaultUnselected={defaultUnselected}
        sortable={false}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

const defaultSelected = {}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 60 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit, sortInfo }) => fetch(DATASET_URL+ '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo): '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      checkboxTabIndex: false
    }
  }

  render() {
    const { checkboxTabIndex } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={checkboxTabIndex}
          onChange={(checkboxTabIndex) => this.setState({ checkboxTabIndex })}
        >
          Use tabIndex for checkboxes - so they can be reached with tab-navigation
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn={{
          checkboxTabIndex: checkboxTabIndex ? 0 : null
        }}
        columns={this.state.columns}
        pagination
        defaultSelected={defaultSelected}
        sortable={false}
        dataSource={this.state.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 <DataGrid /> rows update the row selection.
This prop should be used in combination with checkboxColumn=true.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import people from './people'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'country', flex: 1 },
        { name: 'firstName', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      dataSource: people,
      checkboxOnlyRowSelect: true
    }
  }

  render() {
    const { checkboxOnlyRowSelect } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={checkboxOnlyRowSelect}
          onChange={(checkboxOnlyRowSelect) => this.setState({ checkboxOnlyRowSelect })}
        >
          Update row select using checkbox clicks only
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        checkboxColumn
        checkboxOnlyRowSelect={checkboxOnlyRowSelect}
        columns={this.state.columns}
        defaultSelected={true}
        sortable={false}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
By default, since this is true, any cached values (resulted from calls to setItemPropertyAt or setItemAt) will be cleared when the dataSource is changed.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/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 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandedNodes: defaultExpandedNodes,
      columns: [
        { name: 'name', flex: 1 },
        { name: 'size', defaultWidth: 120 }
      ],
      clearNodeCacheOnDataSourceChange: true,
      dataSource: treeData
    }

    this.onExpandedNodesChange = this.onExpandedNodesChange.bind(this)

    this.refGrid = g => {
      this.grid = g
    }
  }
  onExpandedNodesChange({ expandedNodes }) {
    this.setState({
      expandedNodes
    })
  }

  render() {
    const { clearNodeCacheOnDataSourceChange, expandedNodes } = this.state
    return <div>
      <p>
        <CheckBox
          checked={clearNodeCacheOnDataSourceChange}
          onChange={clearNodeCacheOnDataSourceChange => {
            this.setState({
              clearNodeCacheOnDataSourceChange
            })
          }}
        >Clear node cache on data source change</CheckBox>
      </p>
      <p>
        <Button
          onClick={() => {
            this.grid.setItemPropertyAt(0, 'name', 'Apps')
          }}
        >Set "name" property for first node to "Apps"</Button>
      </p>
      <p>
        <Button
          onClick={() => {
            this.setState({
              dataSource: [].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>
      <DataGrid
        ref={this.refGrid}
        treeColumn="name"
        clearNodeCacheOnDataSourceChange={clearNodeCacheOnDataSourceChange}
        expandedNodes={expandedNodes}
        onExpandedNodesChange={this.onExpandedNodesChange}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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', flex: 1 },
  { name: 'size', defaultWidth: 120 }
]

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 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      treeNestingSize: 22,
      expandedNodes: defaultExpandedNodes,
      collapseChildrenOnAsyncNodeCollapse: true
    }

    this.onExpandedNodesChange = this.onExpandedNodesChange.bind(this)
  }

  onExpandedNodesChange({ expandedNodes }) {
    this.setState({
      expandedNodes
    })
  }

  render() {

    return <div>
      <h3>TreeGrid with async nodes</h3>
      <p>
        <CheckBox checked={this.state.collapseChildrenOnAsyncNodeCollapse} onChange={(collapseChildrenOnAsyncNodeCollapse) => {
          this.setState({
            collapseChildrenOnAsyncNodeCollapse
          })
        }}>
          Collapse children on async node collapse
        </CheckBox>
      </p>
      <DataGrid
        treeColumn="name"
        loadNode={loadNode}
        collapseChildrenOnAsyncNodeCollapse={this.state.collapseChildrenOnAsyncNodeCollapse}
        onExpandedNodesChange={this.onExpandedNodesChange}
        expandedNodes={this.state.expandedNodes}
        style={gridStyle}
        columns={columns}
        dataSource={treeData}
      />

      <p>
        Expanded nodes: {JSON.stringify(this.state.expandedNodes, null, 2)}
      </p>
    </div>
  }
}
export default () => <App />
Object
default: undefined
Specifies groups that should render as collapsed. This is a controlled prop. For the uncontrolled version, see defaultCollapsedGroups.
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).
When using the controlled collapsedGroups, make sure you update the collapsed value when onGroupCollapseChange is triggered.
collapsedGroups=true means all groups are collapsed.
collapsedGroups={} (or collapsedGroups=null) means no group is collapsed (everything is expanded).
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', defaultWidth: 120 },
        { name: 'city', defaultWidth: 120 },
        { name: 'email', flex: 1 }
      ],
      groupBy: ['country','city'],
      collapsedGroups: { 'uk/London': true, 'usa': true },
      dataSource: people
    }

    this.onGroupCollapseChange = this.onGroupCollapseChange.bind(this)
  }
  onGroupCollapseChange(collapsedGroups) {
    this.setState({
      collapsedGroups
    })
  }

  render() {
    const { collapsedGroups } = this.state
    return <div>
      <p>
        Collapsed groups: {JSON.stringify(Object.keys(collapsedGroups))}.
      </p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        collapsedGroups={collapsedGroups}
        onGroupCollapseChange={this.onGroupCollapseChange}
        defaultGroupBy={this.state.groupBy}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
This property is only used when expandedRows=true!
Specifies which rows in the <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandedRows: true,
      collapsedRows: { 1: true, 2: true },
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', defaultWidth: 150 },
        { name: 'country', defaultWidth: 150 },
        { name: 'age', type: 'number', defaultWidth: 150 }
      ],
      dataSource: people
    }
    this.onExpandedRowsChange = this.onExpandedRowsChange.bind(this)
  }
  onExpandedRowsChange({ expandedRows, collapsedRows }) {
    this.setState({
      expandedRows,
      collapsedRows
    })
  }
  render() {
    const { expandedRows, collapsedRows } = this.state
    return <div>
      <div>
        <Button onClick={() => {
          this.setState({
            expandedRows: true
          })
        }} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => {
          this.setState({
            expandedRows: {}
          })
        }}>
          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}
      <DataGrid
        idProperty="id"
        expandedRows={expandedRows}
        collapsedRows={collapsedRows}
        onExpandedRowsChange={this.onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> constrains the column context menu to the <DataGrid /> 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.
For more details, see Using Menu constrainto.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 300 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <p>Column menu constrained to document.documentElement</p>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnContextMenuConstrainTo={true}
        columnContextMenuPosition={"fixed"}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 300 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <p>Column menu constrained to document.documentElement</p>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnContextMenuConstrainTo={true}
        columnContextMenuPosition={"fixed"}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: undefined
Configures the default width for <DataGrid /> columns. If a column specifies a defaultWidth, that value overrides columnDefaultWidth.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name' },
        { name: 'city' },
        { name: 'age', type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        All columns have a default width of 250px
      </div>
      <DataGrid
        idProperty="id"
        columnDefaultWidth={250}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
Controls whether native browser text selection is active in <DataGrid />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 <DataGrid /> headers.
This can be overridden by columns.headerUserSelect, at column-level.
For configuring text-selection in the <DataGrid /> cells, use columnUserSelect.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columnHeaderUserSelect: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', header: 'Name - double click to test selection', flex: 1 }
      ],
      dataSource: people
    }
  }

  render() {
    const { columnHeaderUserSelect } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={columnHeaderUserSelect} onChange={(columnHeaderUserSelect) => this.setState({ columnHeaderUserSelect })}>
          Enable browser text selection in column headers
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnHeaderUserSelect={columnHeaderUserSelect}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
        sortable={false}
      />
    </div>
  }
}

export default () => <App />
Number
default: 50
Specifies the maximum width for all the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 80 },
        { name: 'firstName', header: 'Name maxWidth 200', flex: 2  },
        { name: 'country', header: 'Country maxWidth 250', maxWidth: 250, flex: 3 },
        { name: 'age', flex: 1 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnMaxWidth={200}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: 50
Specifies the minimum width for all the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', minWidth: 40, maxWidth: 40 },
        { name: 'country', minWidth: 200, header: 'Country minWidth: 200', flex: 1 },
        { name: 'firstName', header: 'Name default minWidth', flex: 1 },
        { name: 'age', type: 'number', header: 'Age default minWidth', flex: 1 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <p>Default column minWidth=150</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
        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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      reorderColumns: true,
      columnOrder: ['name', 'age', 'city', 'email', 'id'],
      columns: [
        { name: 'id', type: 'number', defaultWidth: 140, draggable: false, header: 'ID - not draggable' },
        { name: 'name', flex: 1 },
        { name: 'city', minWidth: 80 },
        { name: 'age', minWidth: 80, type: 'number' },
        { name: 'email', minWidth: 80, flex: 1 }
      ],
      dataSource: people
    }
    this.onColumnOrderChange = this.onColumnOrderChange.bind(this)
  }

  onColumnOrderChange(columnOrder) {
    this.setState({
      columnOrder
    })
  }

  render() {
    const { reorderColumns, columnOrder } = this.state
    return <div>
      <div>
        <CheckBox checked={reorderColumns} onChange={(reorderColumns) => this.setState({ reorderColumns })}>
          Enable column reordering
        </CheckBox>
      </div>
      <p>Current column order: {JSON.stringify(columnOrder)}.</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={this.state.groupBy}
        reorderColumns={reorderColumns}
        columnOrder={columnOrder}
        onColumnOrderChange={this.onColumnOrderChange}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', defaultWidth: 280, type: 'number' },
        { name: 'name', defaultWidth: 280 },
        { name: 'city', defaultWidth: 280 },
        { name: 'age', defaultWidth: 280, type: 'number' }
      ]
    }
  }


  render() {
    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>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        columnReorderScrollByAmount={5}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Object[]
default: undefined
An array of columns for the <DataGrid />.
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 <DataGrid />, we treat props as immutable and only update the <DataGrid /> 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 <DataGrid />, instead of building the columns array in the render function of your app and passing it new each time to the <DataGrid />.
Passing a different instance of the columns at each render will slow down the rendering performance of the <DataGrid />.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'firstName', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'age', type: 'number', flex: 1 },
        {
          id: 'desc',
          header: 'Description',
          flex: 2,
          render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
        }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const countryStyle = {
  color: 'green'
}
const redColor = {
  color: 'red'
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', cellDOMProps: { style : redColor } },
        { name: 'name', flex: 1, minWidth: 100 },
        { name: 'country', cellDOMProps: (cellProps) => ({ style: countryStyle }), flex: 1, minWidth: 100 },
        { name: 'city', flex: 1, minWidth: 100 },
        { name: 'age', minWidth: 150, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
bool
default: false
The columns can be locked to the start or to the end of the <DataGrid />.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'name', header: 'Name - defaultLocked', defaultLocked: true, defaultWidth: 200},
        { name: 'city', defaultWidth: 250  },
        { name: 'age', defaultWidth: 250 },
        { name: 'country', defaultWidth: 250 },
        { name: 'id', defaultWidth: 250 }
      ],
      dataSource: people,
    }
  }
  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Make sure the columns do not fit the window, to force the horizontal scroll
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: undefined
Determines whether a column is initially visible or not. Set this to false if you want to hide a column. If not specified (so column.defaultVisible is undefined), the column will be visible.
This is an uncontrolled prop. For the controlled version, use visible.
If you use the controlled prop, make sure you update the column visible prop value when onColumnVisibleChange({ column, visible }) is triggered.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80, defaultVisible: false },
        { name: 'firstName', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Id column is not visible by default. You can enable it from the header menu.
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', defaultWidth: 80, type: 'number' },
        { name: 'name', defaultWidth: 250, header: 'Name - defaultWidth=250' },
        { name: 'city', flex:1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: undefined
Specifies if a specific column can be draggable or not.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = (state) => {
  return [
    { name: 'id', type: 'number', defaultWidth: 80 },
    { name: 'firstName', flex: 1, draggable: state.draggable },
    { name: 'country', flex: 1, draggable: state.draggable },
    { name: 'age', flex: 1, type: 'number', header: 'Age', draggable: state.draggable }
  ]
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.onDraggableChange = this.onDraggableChange.bind(this)

    this.state = {
      draggable: true,
      dataSource: people
    }

    this.state.columns = getColumns(this.state)
  }

  onDraggableChange(value) {
    const draggable = value
    this.setState({
      columns: getColumns(Object.assign({}, this.state, { draggable })),
      draggable
    })
  }

  render() {
    const { draggable } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={draggable} onChange={this.onDraggableChange}>
          Draggable
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = (state) => {
  return [
    { name: 'id', type: 'number', defaultWidth: 80 },
    { name: 'name', flex: 1, editable: state.editable },
    { name: 'country', flex: 1, minWidth: 80 },
    { name: 'city', flex: 1, editable: state.editable },
    { name: 'age', minWidth: 80, type: 'number' }
  ]
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.onEditableChange = this.onEditableChange.bind(this)
    this.onEditComplete = this.onEditComplete.bind(this)

    this.state = {
      editable: true,
      dataSource: people
    }

    this.state.columns = getColumns(this.state)
  }


  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }

  onEditableChange(editable) {
    this.setState({
      columns: getColumns(Object.assign({}, this.state, { editable })),
      editable
    })
  }

  render() {
    const { editable } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={editable} onChange={this.onEditableChange}>
          Make Name and City columns editable
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={this.onEditComplete}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
React.Node
default: undefined
Specifies a custom editor for each column. The <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import NumericEditor from '@zippytech/react-datagrid-pro/NumericEditor'
import '@zippytech/react-datagrid-pro/NumericEditor/index.css'

import BoolEditor from '@zippytech/react-datagrid-pro/BoolEditor'
import '@zippytech/react-datagrid-pro/BoolEditor/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people.map(p=>Object.assign({}, p)),
      columns: [
        { name: 'id', type: 'number', flex: 1 },
        { name: 'name', flex: 1 },
        { name: 'age', flex: 1, editor: NumericEditor },
        { name: 'student', flex: 1, render: ({ value }) => value? 'yes':'no', editor: BoolEditor },
        { name: 'country', flex: 1, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1 }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div style={{marginBottom: 20}}>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={this.onEditComplete}
        editable={true}
        columns={this.state.columns}
        dataSource={this.state.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<DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import NumericEditor from '@zippytech/react-datagrid-pro/NumericEditor'
import '@zippytech/react-datagrid-pro/NumericEditor/index.css'

import BoolEditor from '@zippytech/react-datagrid-pro/BoolEditor'
import '@zippytech/react-datagrid-pro/BoolEditor/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name', flex: 1, minWidth: 200, maxWidth: 300 },
        { name: 'age', flex: 1, type: 'number', editor: NumericEditor },
        { name: 'student',
          width: 100,
          editor: BoolEditor,
          render: ({ value }) => value? 'yes':'no',
          editorProps: {
            style: { background: 'rgb(189, 236, 255)' }
          }
        },
        { name: 'country', flex: 1, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1 }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={this.onEditComplete}
        editable={true}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool|Number
default: 250
If a numeric value is specified, it is used to delay (actually debounce) the filtering for the column, as the user is typing and changing the filter value.
When false or 0, no delay is used.
In most cases, using a filtering delay is highly recommended, both for the user experience & performance.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      filterValue: [
        { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name', flex: 1, filterDelay: 500 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
React.Component
default: undefined
Specifies the editor that should be used for the filter.
Starting with version 2.0.0, the filter editors are not embeded in the <DataGrid />, but have to be explicitly imported. Here is the list of available imports:
  • @zippytech/react-datagrid-pro/StringFilter (the css is at @zippytech/react-datagrid-pro/StringFilter/index.css)
  • @zippytech/react-datagrid-pro/NumberFilter (the css is at @zippytech/react-datagrid-pro/NumberFilter/index.css)
  • @zippytech/react-datagrid-pro/BoolFilter (the css is at @zippytech/react-datagrid-pro/BoolFilter/index.css)
  • @zippytech/react-datagrid-pro/SelectFilter (the css is at @zippytech/react-datagrid-pro/SelectFilter/index.css)
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 assign from 'object-assign';

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(assign({}, this.props.filterValue, { value }));
  }

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

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

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

    return this.props.render(
      <input
        type="text"
        onChange={this.onChange}
        className="zippy-react-datagrid__column-header__filter zippy-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}
    />
  );
}
As of version 2.0.0, the filterEditor can no longer be string.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import NumberFilter from '@zippytech/react-datagrid-pro/NumberFilter'
import '@zippytech/react-datagrid-pro/NumberFilter/index.css'

import BoolFilter from '@zippytech/react-datagrid-pro/BoolFilter'
import '@zippytech/react-datagrid-pro/BoolFilter/index.css'

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

const gridStyle = { minHeight: 550 }

const filterTypes = Object.assign({}, DataGrid.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
        }
      }
    ]
  }
})

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      enableFiltering: true,
      filterValue: [
        { name: 'country', operator: 'europe', type: 'country', value: true },
        { name: 'age', operator: 'gte', type: 'number', minWidth: 200, value: 21 }
      ],
      columns: [
        { name: 'id', maxWidth: 100, type: 'number' },
        { name: 'name', flex: 1, maxWidth: 200 },
        { name: 'country',
          header: 'Country - with Europe checkbox filter',
          flex: 1,
          filterEditor: BoolFilter,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1, minWidth: 200 },
        { name: 'age', minWidth: 150, type: 'number', filterEditor: NumberFilter }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Object
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.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import NumberFilter from '@zippytech/react-datagrid-pro/NumberFilter'
import '@zippytech/react-datagrid-pro/NumberFilter/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      filterValue: [
        { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', maxWidth: 100, type: 'number' },
        { name: 'name', flex: 1, minWidth: 200, maxWidth: 300, filterEditorProps: { style: { background: 'Bisque' } } },
        { name: 'age', flex: 1, type: 'number', filterEditor: NumberFilter },
        { name: 'country', flex: 1, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1 }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.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 />
String
default: undefined
Specifies the filter type. Is overridden by filterValue.type.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import NumberFilter from '@zippytech/react-datagrid-pro/NumberFilter'
import '@zippytech/react-datagrid-pro/NumberFilter/index.css'


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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      filterValue: [
        { name: 'name', operator: 'startsWith' },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', maxWidth: 100, type: 'number' },
        { name: 'name', flex: 1, minWidth: 200, maxWidth: 300, filterType: 'string' },
        { name: 'age', flex: 1, type: 'number', filterEditor: NumberFilter },
        { name: 'country', flex: 1, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1 }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.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 />
Number
default: undefined
Specifies the flex amount for the column.
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.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', flex: 1 },
        { name: 'country', flex: 2 },
        { name: 'firstName', flex: 3 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Columns with flex values of 1, 2, and 3
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = (state) => {
  return [
    { name: 'id', type: 'number', defaultWidth: 80, editable: false },
    { name: 'name', flex: 1, getEditStartValue: (value) => Promise.resolve(value + '!!!') },
    { name: 'country', flex: 1, minWidth: 80 },
    { name: 'city', flex: 1, getEditStartValue: (value) => value + '!!!' },
    { name: 'age', minWidth: 80, type: 'number', getEditStartValue: (value) => Promise.resolve(value + '!!!') }
  ]
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.onEditComplete = this.onEditComplete.bind(this)

    this.state = {
      editable: true,
      dataSource: people
    }

    this.state.columns = getColumns(this.state)
  }

  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }

  render() {
    return <div>
      <p>NAME, CITY and AGE columns start the edit by adding a "!!!" at the end of the actual value</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        editable
        onEditComplete={this.onEditComplete}
        columns={this.state.columns}
        dataSource={this.state.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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80 },
  { name: 'firstName', group: 'personalInfo', flex: 2 },
  { name: 'age', group: 'personalInfo', type: 'number' },
  { name: 'email', group: 'contactInfo', flex: 2 },
  { name: 'phone', group: 'contactInfo' },
  { name: 'city', group: 'location' },
  { name: 'streetName', group: 'street', flex: 1 },
  { name: 'streetNo', group: 'street', type: 'number' }
]
const groups = [
  { name: 'street', group: 'location' },
  { name: 'personalInfo', group: 'details' },
  { name: 'contactInfo', group: 'details' },
  { name: 'location', group: 'details' },
  { name: 'details', header: 'Detailed info' }
]

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>
  <DataGrid
    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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', groupBy: false, type: 'number', defaultWidth: 50 },
        { name: 'firstName', defaultWidth: 150 },
        { name: 'lastName', defaultWidth: 150 },
        { name: 'email', groupBy: false, defaultWidth: 150 },
        {
          name: 'permissionToCall',
          defaultWidth: 200,
          render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
          renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
        }
      ],
      dataSource: ({ skip, limit, sortInfo, groupBy }) => 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');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      groupBy: []
    }

    this.onGroupByChange = this.onGroupByChange.bind(this)
  }

  onGroupByChange(groupBy) { this.groupBy(groupBy) }

  groupBy(groupBy) {
    this.setState({ groupBy })
  }

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

export default () => <App />
Fn(value)
default: undefined
Specifies a custom function to return the grouping value.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

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 },
  { name: 'city',
    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', flex: 2 },
  { name: 'age', type: 'number', minWidth: 50 },
  { name: 'email', flex: 2 },
  { name: 'phone', flex: 1 },
  { name: 'streetName', flex: 1 },
  { name: 'streetNo', type: 'number', minWidth: 50 }
]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns,
      dataSource
    }

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

export default () => <App />
Fn(value, { data, fieldName })
default: undefined
Specifies a custom function to use for determining grouping when groupBy is used.
When no column.renderGroupTitle is specified, this function is used instead for rendering the group title.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const columns = [
  { name: 'id', type: 'number', minWidth: 50 },
  { name: 'firstName', group: 'personalInfo', flex: 2 },
  { name: 'age', group: 'personalInfo', type: 'number', minWidth: 50 },
  { name: 'email', group: 'contactInfo', flex: 2 },
  { name: 'phone', group: 'contactInfo', flex: 1 },
  { name: 'city', group: 'location', flex: 1,
    groupToString: (value) => {
      if (europeCities[value]) {
        return 'Europe'
      }

      return 'USA'
    }
  },
  { name: 'streetName', group: 'street', flex: 1 },
  { name: 'streetNo', group: 'street', type: 'number', minWidth: 50 }
]

const groups = [
  { name: 'street', group: 'location' },
  { name: 'personalInfo', group: 'details', header: 'Information about you' },
  { name: 'contactInfo', group: 'details', header: <span style={{ color: 'green' }}>Contact</span> },
  { name: 'location', group: 'details', header: <span style={{ color: 'red' }}>Where you live</span> },
  { name: 'details', header: 'Detailed info' }
]

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>
  <DataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>
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 <DataGrid /> 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 <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80 },
  { name: 'name', flex: 1, header: <h3 style={{margin: 0, color: 'tomato', fontWeight: 'bold'}}>First Name</h3> },
  { name: 'city', flex: 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 () => <DataGrid
  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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 80, type: 'number' },
        { name: 'name', flex: 1, headerAlign: 'start' },
        { name: 'city', flex: 1, headerAlign: 'center' },
        { name: 'age', type: 'number', flex: 1, headerAlign: 'end' }
      ],
      dataSource: people
    }
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Columns with headerAlign none, start, center and end
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const countryStyle = {
  color: 'green'
}
const redColor = {
  color: 'red'
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', headerDOMProps: { style : redColor } },
        { name: 'name', flex: 1, minWidth: 100 },
        { name: 'country', headerDOMProps: { style: countryStyle }, flex: 1, minWidth: 100 },
        { name: 'city', flex: 1, minWidth: 100 },
        { name: 'age', minWidth: 150, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      textEllipsis: true
    }

    this.onTextEllipsisChange = this.onTextEllipsisChange.bind(this)

    this.state.columns = getColumns(true)
  }

  onTextEllipsisChange(textEllipsis) {
    this.setState({
      columns: getColumns(textEllipsis),
      textEllipsis
    })
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={this.state.textEllipsis}
          onChange={this.onTextEllipsisChange}
        >
          Show text ellipsis on description header and column.
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columnHeaderUserSelect: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', header: 'Name - double-click to test selection', flex: 1, minWidth: 250, },
        { name: 'age', minWidth: 250, flex: 1, header: 'double-click to select', headerUserSelect: true }
      ],
      dataSource: people
    }
  }

  render() {
    const { columnHeaderUserSelect } = this.state
    return <div>
      <div>
        <CheckBox checked={columnHeaderUserSelect} onChange={(columnHeaderUserSelect) => this.setState({ columnHeaderUserSelect })}>
          Enable browser text selection in headers
        </CheckBox>
      </div>
      <p>The last column header is always selectable, since it's configured with headerUserSelect: true</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnHeaderUserSelect={columnHeaderUserSelect}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
        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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', defaultWidth: 80, type: 'number' },
        { name: 'name', flex: 1, headerVerticalAlign: 'top' },
        { name: 'city', flex: 1, headerVerticalAlign: 'middle' },
        { name: 'age', flex: 1, type: 'number', headerVerticalAlign: 'bottom' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Header columns with headerVerticalAlign none, top, middle and bottom
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        rowHeight={70}
        headerHeight={100}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const getColumns = ({nameHideable}) => {
  return [
    { name: 'id', type: 'number', defaultWidth: 80 },
    { name: 'name', flex: 1, hideable: nameHideable },
    { name: 'country', flex: 1, minWidth: 80 },
    { name: 'city', flex: 1 },
    { name: 'age', minWidth: 80, type: 'number' }
  ]
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      nameHideable: false,
      dataSource: people
    }

    this.state.columns = getColumns(this.state)
  }

  render() {
    const { nameHideable } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={nameHideable} onChange={(nameHideable) => {
          this.setState({
            nameHideable,
            columns: getColumns({nameHideable})
          })
        }}>
          Can hide Name column
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'firstName', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'age', type: 'number', flex: 1 },
        {
          id: 'desc',
          header: 'Description',
          flex: 2,
          render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
        }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid />.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

  return [
    Object.assign({ name: 'name', defaultWidth: 250 }, lockedStartProps),
    { name: 'city', defaultWidth: 250 },
    { name: 'age', defaultWidth: 250 },
    { name: 'country', defaultWidth: 250 },
    Object.assign({ name: 'id', defaultWidth: 250}, lockedEndProps)
  ]
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      lockStart: true,
      lockEnd: false,
      columns: getColumns('start'),
      dataSource: people
    }
  }

  render() {
    return <div>
      <div>
        Make sure the columns do not fit the window, to force the horizontal scroll
      </div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={this.state.lockStart}
          onChange={lockStart => this.setState({ lockStart, columns: getColumns(lockStart, this.state.lockEnd) })}
        >
          Lock at start
        </CheckBox>
        <CheckBox
          checked={this.state.lockEnd}
          onChange={lockEnd => this.setState({ lockEnd, columns: getColumns(this.state.lockStart, lockEnd) })}
        >
          Lock at end
        </CheckBox>
      </div>
      <DataGrid
        key={this.state.lockPosition}
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 80 },
        { name: 'firstName', header: 'Name maxWidth 200', flex: 2  },
        { name: 'country', header: 'Country maxWidth 250', maxWidth: 250, flex: 3 },
        { name: 'age', flex: 1 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnMaxWidth={200}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', minWidth: 40, maxWidth: 40 },
        { name: 'country', minWidth: 200, header: 'Country minWidth: 200', flex: 1 },
        { name: 'firstName', header: 'Name default minWidth', flex: 1 },
        { name: 'age', type: 'number', header: 'Age default minWidth', flex: 1 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <p>Default column minWidth=150</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
        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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { id: 'uid', render: ({data}) => data.id, defaultWidth: 80 },
        { name: 'firstName', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      dataSource: people
    }
  }
  render() {
    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>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const onCountryRender = (cellProps) => {
  cellProps.style.color = 'red'
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name', flex: 1, minWidth: 100 },
        { name: 'country', onRender: onCountryRender, flex: 1, minWidth: 100 },
        { name: 'city', flex: 1, minWidth: 100 },
        { name: 'age', minWidth: 150, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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 <DataGrid /> has row expand enabled - see expandedRows, this function will be present, and can be used to set the toggle state of the current row.
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 <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import flags from './flags'

const gridStyle = { maxHeight: 207 }

const columns = [
  { name: 'firstName', flex: 1 },
  { name: 'lastName', flex: 1 },
  {
    name: 'country',
    defaultWidth: 100,
    textAlign: 'center',
    render: ({ value }) => flags[value] ? <img src={flags[value]} style={{ verticalAlign: 'middle'}} /> : 'unknown'
  },
  { id: 'fullName', header: 'Full Name', minWidth: 100, flex: 1, render: ({ data }) => data.firstName + ' ' + data.lastName },
  {
    name: 'age',
    defaultWidth: 80,
    render: ({ value }) => <span style={{ color: value < 30 ? 'green' : '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 () => <DataGrid
  idProperty="id"
  columns={columns}
  dataSource={dataSource}
  style={gridStyle}
/>
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 400 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.gridRef = grid => {
      this.grid = grid
    }

    this.onSearchChange = this.onSearchChange.bind(this)

    const render = ({ value }) => {
      const { lowerSearchText } = this.state
      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>
      ]
    }

    const shouldComponentUpdate = () => true

    this.state = {
      dataSource: people,
      searchText: '',
      columns: [
        { name: 'id', minWidth: 50, type: 'number', render, shouldComponentUpdate },
        { name: 'name', flex: 1, render, shouldComponentUpdate },
        { name: 'country', flex: 1, minWidth: 100, render: ({ value })=> flags[value]? <img src={flags[value]} />: value, shouldComponentUpdate },
        { name: 'city', flex: 1, minWidth: 100, render, shouldComponentUpdate },
        { name: 'age', minWidth: 80, type: 'number',render, shouldComponentUpdate }
      ]
    }
  }

  onSearchChange({ target: { value }}) {
    const visibleColumns = this.grid.getVisibleColumns()
    const searchText = value

    const lowerSearchText = searchText.toLowerCase()

    this.setState({
      searchText,
      lowerSearchText,
      dataSource: 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)
      })
    })
  }

  render() {
    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: <input type="text" style={{ padding: 5 }} value={this.state.searchText} onChange={this.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>
      <DataGrid
        ref={this.gridRef}
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import NumericEditor from '@zippytech/react-datagrid-pro/NumericEditor'
import '@zippytech/react-datagrid-pro/NumericEditor/index.css'

import BoolEditor from '@zippytech/react-datagrid-pro/BoolEditor'
import '@zippytech/react-datagrid-pro/BoolEditor/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name', flex: 1, minWidth: 200, maxWidth: 300 },
        { name: 'age', flex: 1, type: 'number', editor: NumericEditor },
        { name: '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: 'gray',
                  color: 'white',
                  left: 0,
                  top: 0
                }}
              >
                {editorProps.value ? 'X' : 'O'}
            </div>
          }
        },
        { name: 'country', flex: 1, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1 }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={this.onEditComplete}
        editable={true}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Fn({ value, name, namePath, ... }, 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', groupBy: false, type: 'number', defaultWidth: 70 },
        { name: 'firstName', defaultWidth: 200 },
        { name: 'lastName', defaultWidth: 200 },
        { name: 'email', groupBy: false, defaultWidth: 200 },
        {
          name: 'permissionToCall', defaultWidth: 200,
          render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
          renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
        }
      ],
      dataSource: ({ skip, limit, sortInfo, groupBy }) => 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');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      groupBy: []
    }

    this.onGroupByChange = this.onGroupByChange.bind(this)
  }

  onGroupByChange(groupBy) { this.groupBy(groupBy) }

  groupBy(groupBy) {
    this.setState({ groupBy })
  }

  render() {
    return <div>
      <p><Button onClick={() => this.groupBy(['permissionToCall', 'lastName'])}>Group by permissionToCall and lastName</Button></p>
      <p><Button onClick={() => this.groupBy([])}>Remove grouping</Button></p>
      <p>In this example, you cannot group by id or email.</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        groupBy={this.state.groupBy}
        onGroupByChange={this.onGroupByChange}
        columns={this.state.columns}
        dataSource={this.state.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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

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

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

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

import flags from './flags'

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

const columns = [
  { name: 'id', header: 'ID - unsortable', sortable: false, defaultWidth: 120 },
  { name: 'firstName', flex: 1, renderHeader },
  { name: 'lastName', flex: 1, renderHeader },
  {
    name: 'country',
    defaultWidth: 100,
    renderHeader,
    render: ({ value }) => flags[value] ? <img src={flags[value]} style={{ verticalAlign: 'middle'}} /> : 'unknown'
  },
  { id: 'fullName', header: 'Full Name', renderHeader, minWidth: 50, flex: 1, render: ({ data }) => data.firstName + ' ' + data.lastName },
  {
    name: '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 () => <DataGrid
  idProperty="id"
  columns={columns}
  style={gridStyle}
  defaultSortInfo={defaultSortInfo}
  renderSortTool={renderSortTool}
  dataSource={dataSource}
/>
bool
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.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

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

    this.ref = n => {
      this.node = n;
    };
  }
  render() {
    return <input {...this.props} ref={this.ref} />;
  }
  componentDidUpdate(prevProps) {
    if (this.props.autoFocus && !prevProps.autoFocus) {
      this.node.focus();
    }
  }
}

class App extends React.Component {
  constructor(props) {
    super(props)

    const nameColumn = {
      name: 'name',
      flex: 1, minWidth: 400,
      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
                );
              }
            }}
          />
        );
      }
    }

    this.state = {
      dataSource: people.map(p=> Object.assign({}, p)),
      columns: [
        { name: 'id', minWidth: 300, type: 'number' },
        nameColumn,
        { name: 'country', flex: 1, minWidth: 400, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1, minWidth: 400 },
        { name: 'age', minWidth: 350, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    console.log(value, columnId, rowIndex)
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <h3>NAME column already renders an editor</h3>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={this.onEditComplete}
        editable={true}
        columns={this.state.columns}
        dataSource={this.state.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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

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

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

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

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

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80, renderSortTool },
        { name: 'firstName', flex: 1, renderSortTool },
        { name: 'country', flex: 1, renderSortTool },
        { name: 'age', type: 'number', flex: 1, renderSortTool }
      ],
      dataSource: people
    }
  }
  render() {
    const { sortable } = this.state
    return <div>
      <DataGrid
        idProperty="id"
        defaultSortInfo={defaultSortInfo}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.onResizableChange = this.onResizableChange.bind(this)

    this.state = {
      resizable: true,
      dataSource: people
    }

    this.state.columns = getColumns(this.state)
  }

  onResizableChange(resizable) {
    this.setState({
      columns: getColumns(resizable),
      resizable
    })
  }

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

export default () => <App />
Fn()
default: undefined
Needs to be used when you have a custom column.render function which is not pure, but uses variables from the outer context. Otherwise, if not using shouldComponentUpdate: () => true in these cases, you end up with the cells not being updated/re-rendered properly.
The <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 400 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.gridRef = grid => {
      this.grid = grid
    }

    this.onSearchChange = this.onSearchChange.bind(this)

    const render = ({ value }) => {
      const { lowerSearchText } = this.state
      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>
      ]
    }

    const shouldComponentUpdate = () => true

    this.state = {
      dataSource: people,
      searchText: '',
      columns: [
        { name: 'id', minWidth: 50, type: 'number', render, shouldComponentUpdate },
        { name: 'name', flex: 1, render, shouldComponentUpdate },
        { name: 'country', flex: 1, minWidth: 100, render: ({ value })=> flags[value]? <img src={flags[value]} />: value, shouldComponentUpdate },
        { name: 'city', flex: 1, minWidth: 100, render, shouldComponentUpdate },
        { name: 'age', minWidth: 80, type: 'number',render, shouldComponentUpdate }
      ]
    }
  }

  onSearchChange({ target: { value }}) {
    const visibleColumns = this.grid.getVisibleColumns()
    const searchText = value

    const lowerSearchText = searchText.toLowerCase()

    this.setState({
      searchText,
      lowerSearchText,
      dataSource: 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)
      })
    })
  }

  render() {
    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: <input type="text" style={{ padding: 5 }} value={this.state.searchText} onChange={this.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>
      <DataGrid
        ref={this.gridRef}
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      showColumnMenuFilterOptions: true,
      filterValue: [
        { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(showColumnMenuFilterOptions) => {
            this.setState({
              showColumnMenuFilterOptions,
              columns: [
                { name: 'id', type: 'number', defaultWidth: 80 },
                { name: 'name', flex: 1, showColumnMenuFilterOptions },
                { name: 'country', flex: 1,
                  render: ({ value })=> flags[value]? <img src={flags[value]} />: value
                },
                { name: 'city', flex: 1 },
                { name: 'age', flex: 1, type: 'number' }
              ]
            })
          }}
          checked={this.state.showColumnMenuFilterOptions}>
          Display show/hide filtering row option for NAME column in column menu
        </CheckBox>
      </div>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      showColumnMenuGroupOptions: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(showColumnMenuGroupOptions) => {
            this.setState({
              showColumnMenuGroupOptions,
              columns: [
                { name: 'id', type: 'number', defaultWidth: 80 },
                { name: 'name', flex: 1, showColumnMenuGroupOptions },
                { name: 'country', flex: 1,
                  render: ({ value })=> flags[value]? <img src={flags[value]} />: value
                },
                { name: 'city', flex: 1 },
                { name: 'age', flex: 1, type: 'number' }
              ]
            })
          }}
          checked={this.state.showColumnMenuGroupOptions}>
          Show lock/unlock loption for NAME column in column menu
        </CheckBox>
      </div>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      showColumnMenuLockOptions: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(showColumnMenuLockOptions) => {
            this.setState({
              showColumnMenuLockOptions,
              columns: [
                { name: 'id', type: 'number', defaultWidth: 80 },
                { name: 'name', flex: 1, showColumnMenuLockOptions },
                { name: 'country', flex: 1,
                  render: ({ value })=> flags[value]? <img src={flags[value]} />: value
                },
                { name: 'city', flex: 1 },
                { name: 'age', flex: 1, type: 'number' }
              ]
            })
          }}
          checked={this.state.showColumnMenuLockOptions}>
          Show lock/unlock option for NAME column in column menu
        </CheckBox>
      </div>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      showColumnMenuSortOptions: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(showColumnMenuSortOptions) => {
            this.setState({
              showColumnMenuSortOptions,
              columns: [
                { name: 'id', type: 'number', defaultWidth: 80 },
                { name: 'name', flex: 1, showColumnMenuSortOptions },
                { name: 'country', flex: 1,
                  render: ({ value })=> flags[value]? <img src={flags[value]} />: value
                },
                { name: 'city', flex: 1 },
                { name: 'age', flex: 1, type: 'number' }
              ]
            })
          }}
          checked={this.state.showColumnMenuSortOptions}>
          Show lock/unlock loption for NAME column in column menu
        </CheckBox>
      </div>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Controls whether the current column header has menu integration enabled or not.
This overrides showColumnMenuTool, at column-level.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      showColumnMenuTool: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(showColumnMenuTool) => {
            this.setState({
              showColumnMenuTool,
              columns: [
                { name: 'id', type: 'number', defaultWidth: 80 },
                { name: 'name', flex: 1, showColumnMenuTool },
                { name: 'country', flex: 1,
                  render: ({ value })=> flags[value]? <img src={flags[value]} />: value
                },
                { name: 'city', flex: 1 },
                { name: 'age', flex: 1, type: 'number' }
              ]
            })
          }}
          checked={this.state.showColumnMenuTool}>
          Show NAME column header tool
        </CheckBox>
      </div>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      showColumnMenuToolOnHover: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(showColumnMenuToolOnHover) => {
            this.setState({
              showColumnMenuToolOnHover,
              columns: [
                { name: 'id', type: 'number', defaultWidth: 80 },
                { name: 'name', flex: 1, showColumnMenuToolOnHover },
                { name: 'country', flex: 1,
                  render: ({ value })=> flags[value]? <img src={flags[value]} />: value
                },
                { name: 'city', flex: 1 },
                { name: 'age', flex: 1, type: 'number' }
              ]
            })
          }}
          checked={this.state.showColumnMenuToolOnHover}>
          Show NAME column header tool on hover
        </CheckBox>
      </div>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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', type: 'number', defaultWidth: 80 },
  {
    name: 'person',
    flex: 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',
    maxWidth: 400,
    defaultWidth: 150,
    type: 'number',
    render: ({ data }) => <span>{data.person.age}</span>
  }
]

class App extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    return <div>
      <p>
        In this example, you can sort the person column by the last name.
      </p>
      <DataGrid
        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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      dataSource: people,
      columns:  [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'firstName', flex: 1, sortable: true },
        { name: 'country', flex: 1, sortable: false }
      ]
    }
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Columns with sortable unset, true and false
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }


class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', flex: 1  },
        { name: 'name', flex: 1, textAlign: 'start' },
        { name: 'city', flex: 1, textAlign: 'center' },
        { name: 'age', flex: 1, type: 'number', textAlign: 'end' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Columns with textAlign none, start, center and end
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      textEllipsis: true
    }

    this.onTextEllipsisChange = this.onTextEllipsisChange.bind(this)

    this.state.columns = getColumns(true)
  }

  onTextEllipsisChange(textEllipsis) {
    this.setState({
      columns: getColumns(textEllipsis),
      textEllipsis
    })
  }

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

export default () => <App />
String
default: undefined
A value for aligning text on the vertical axis inside <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1, textVerticalAlign: 'top' },
        { name: 'city', flex: 1, textVerticalAlign: 'middle' },
        { name: 'age', type: 'number', flex: 1, textVerticalAlign: 'bottom' }
      ]
    }
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        Column headers with none, top, middle and bottom vertical alignment
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        rowHeight={100}
        headerHeight={100}
        dataSource={this.state.dataSource}
      />
    </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<DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80 },
  { name: 'name', flex: 1 },
  { name: 'city', flex: 1 },
  { name: 'age', type: 'number', flex: 1 }
]

const gridStyle = {
  maxHeight: 400
}

export default () => <DataGrid
  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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columnUserSelect: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', header: 'Name - test cell selection on this column', flex: 1, minWidth: 250, },
        { name: 'age', minWidth: 250, flex: 1, header: 'content can always be selected' }
      ],
      dataSource: people
    }
  }

  render() {
    const { columnUserSelect } = this.state
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={columnUserSelect} onChange={(columnUserSelect) => this.setState({ columnUserSelect })}>
          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>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnUserSelect={columnUserSelect}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columnIdVisible: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'firstName', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      dataSource: people
    }
    this.setVisible = this.setVisible.bind(this)
  }

  setVisible(visible) {
    this.setState({
      columns: this.state.columns.map(c => {
        if (c.name === 'id') {
          c = Object.assign({}, c, { visible })
        }
        return c
      }),
      columnIdVisible: visible
    })
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={this.state.columnIdVisible}
          onChange={this.setVisible}
        >
          Show Id column
        </CheckBox>
      </div>
      <DataGrid
        key={this.state.columnIdVisible}
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', width: 80, type: 'number' },
        { name: 'name', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', width: 80, type: 'number' }
      ]
    }

    this.onColumnResize = this.onColumnResize.bind(this)
  }

  onColumnResize({ column, flex, width }) {
    this.setState({
      columns: this.state.columns.map(c => {
        if (c.name === column.name) {
          c = Object.assign({}, c, { width, flex })
        }
        return c
      })
    })
  }

  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        First and last columns with fixed width
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        onColumnResize={this.onColumnResize}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid />.
This can be overridden by columns.userSelect, at column-level.
For configuring text-selection in the <DataGrid /> header, use columnHeaderUserSelect.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columnUserSelect: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', header: 'Name - try selecting text in cells', flex: 1, minWidth: 250, },
        { name: 'age', flex: 1, minWidth: 250, header: 'Cells in this col are always selectable - userSelect: true', userSelect: true }
      ],
      dataSource: people
    }
  }

  render() {
    const { columnUserSelect } = this.state
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={columnUserSelect} onChange={(columnUserSelect) => this.setState({ columnUserSelect })}>
          Enable browser text selection in cells
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columnUserSelect={columnUserSelect}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Array|Promise|Fn()=>Promise
default: undefined
Specifies the source of data for <DataGrid /> contents. The <DataGrid /> 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 <DataGrid />, 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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit, sortInfo }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      })
    }
  }

  render() {
    return <div>
      <DataGrid idProperty="id" style={gridStyle}
        columns={this.state.columns}
        pagination
        defaultLimit={15}
        defaultSkip={15}
        pageSizes={[10, 15, 30]}
        dataSource={this.state.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 <DataGrid /> (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<DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 300 }

const defaultActiveCell = [4,1]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      enableKeyboardNavigation: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', minWidth: 80, type: 'number' }
      ],
      dataSource: people
    }
  }

  render() {
    const { enableKeyboardNavigation } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={enableKeyboardNavigation} onChange={(enableKeyboardNavigation) => this.setState({ enableKeyboardNavigation })}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultActiveCell={defaultActiveCell}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Specifies the default active index for the <DataGrid />. 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 <DataGrid /> with keyboard navigation, as the active index is updated, the <DataGrid /> is automatically scrolled to show the currently active row in the viewport.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 500 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', minWidth: 100, flex: 1 },
        { name: 'age', minWidth: 80, type: 'number' }
      ],
      dataSource: people
    }
  }

  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultActiveIndex={1}
        enableKeyboardNavigation={true}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Array
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 array of strings - each string representing a cell. 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const defaultCellSelection = ["2,name", "2,city"]

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', resizable: false, sortable: false, header: 'ID - unsortable' },
        { name: 'name', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', defaultWidth: 100, type: 'number' }
      ],
      dataSource: people,
      cellSelection: defaultCellSelection
    }
    this.onCellSelectionChange = this.onCellSelectionChange.bind(this)
  }
  onCellSelectionChange(cellSelection) {
    this.setState({
      cellSelection
    })
  }
  render() {
    return <div>
      <p>
        Selected cells: {this.state.cellSelection.length == 0 ? 'none' : JSON.stringify(this.state.cellSelection)}.
      </p>
      <DataGrid
        idProperty="id"
        defaultCellSelection={defaultCellSelection}
        onCellSelectionChange={this.onCellSelectionChange}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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.
defaultCollapsedGroups={} (or collapsedGroups=null) means no group is collapsed (everything is expanded).
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'email', flex: 1 }
      ],
      groupBy: ['country','city'],
      dataSource: people
    }
  }

  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultCollapsedGroups={defaultCollapsedGroups}
        defaultGroupBy={this.state.groupBy}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
This property is only used when defaultExpandedRows=true!
Specifies which rows in the <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandedRows: true,
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', defaultWidth: 150 },
        { name: 'country', defaultWidth: 150 },
        { name: 'age', type: 'number', defaultWidth: 150 }
      ],
      dataSource: people
    }
  }
  render() {
    const { expandedRows } = this.state
    return <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          this.setState({
            expandedRows: true
          })
        }} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => {
          this.setState({
            expandedRows: {}
          })
        }}>
          Collapse all
        </Button>
      </div>
      <DataGrid
        idProperty="id"
        expandedRows={expandedRows}
        defaultCollapsedRows={defaultCollapsedRows}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
Specifies which nodes in the <DataGrid /> 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.
Object|Boolean
default: undefined
Specifies which rows in the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandedRows: { 3: true, 2: true },
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', defaultWidth: 150 },
        { name: 'country', defaultWidth: 150 },
        { name: 'age', type: 'number', defaultWidth: 150 }
      ],
      dataSource: people
    }
    this.onExpandedRowsChange = this.onExpandedRowsChange.bind(this)
  }
  onExpandedRowsChange({ expandedRows }) {
    this.setState({
      expandedRows
    })
  }
  render() {
    const { expandedRows } = this.state
    return <div>
      <p>
        Expanded rows: {expandedRows == null ? 'none' : JSON.stringify(expandedRows, null, 2)}.
      </p>
      <DataGrid
        idProperty="id"
        defaultExpandedRows={expandedRows}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        onExpandedRowsChange={this.onExpandedRowsChange}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Array[Object]
default: undefined
Specifies a default filter value for the <DataGrid />. When this is specified, unless enableFiltering is false, the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      filterValue: [
        { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', maxWidth: 100, type: 'number' },
        { name: 'name', flex: 1, minWidth: 200, maxWidth: 300 },
        { name: 'age', flex: 1, type: 'number' },
        { name: 'country', flex: 1, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1 }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.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 />
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 <DataGrid /> 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<DataGrid />. See hideGroupByColumns if you want to change that.
In the example below, try dragging the age column header to the grouping toolbar in the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'country', flex: 1 },
        { name: 'firstName', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      dataSource: people
    }
  }

  render() {
    const { hideGroupByColumns } = this.state
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={['country']}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: 50
The default page size for the <DataGrid />, 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+limit).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      })
    }

  }

  render() {
    return <div>
      <DataGrid
        sortable={false}
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        pagination
        pageSizes={this.state.pageSizes}
        dataSource={this.state.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 <DataGrid />. If you are using the controlled loading, you need to make sure the loading mask is displayed while fetching remote data.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'name', flex: 1 },
        { name: 'age' }
      ],
      dataSource: [],
      defaultLoading: true
    }
  }

  // Let's make this intentionally slow, in order to see the loading better
  mockTimeConsumingLoad() {
    const dataSource = 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)
    })

    this.setState({
      dataSource
    })
  }

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

export default () => <App />
String|Number|Object
default: undefined
Specifies the default selected row (or rows) in the <DataGrid />. 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 <DataGrid /> 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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      dataSource: people
    }
    this.onSelectionChange = this.onSelectionChange.bind(this)
  }
  onSelectionChange({ selected: selectedMap, data }) {
    this.setState({
      selected: selectedMap
    })
  }
  render() {
    const { selected } = this.state
    return <div>
      <p>
        Selected rows: {selected == null ? JSON.stringify(Object.keys(defaultSelected)) : JSON.stringify(Object.keys(selected))}.
      </p>
      <DataGrid
        idProperty="id"
        defaultSelected={defaultSelected}
        onSelectionChange={this.onSelectionChange}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: 0
The default skip value for the <DataGrid />, 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 <DataGrid /> has remote pagination) can be reloaded with the correct skip value.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit, sortInfo }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      pageSizes: [10, 15, 30]
    }
  }

  render() {
    return <div>
      <DataGrid idProperty="id" style={gridStyle}
        columns={this.state.columns}
        pagination
        defaultLimit={15}
        defaultSkip={45}
        pageSizes={this.state.pageSizes}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Object|Object[]
default: undefined
Specifies the default sort order for the <DataGrid />. This is an uncontrolled prop. For the controlled version, see sortInfo.
When uncontrolled sorting is used, the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 80, sortable: false },
        { name: 'name', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      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 }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        defaultSortInfo={defaultSortInfo}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
        style={gridStyle}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
Used in combination with remote dataSource and defaultSelected.
Specifies which <DataGrid /> 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 from 'react'
                import DataGrid from '@zippytech/react-datagrid-pro'
                import '@zippytech/react-datagrid-pro/index.css'
                import CheckBox from '@zippytech/react-toolkit/CheckBox'
                import '@zippytech/react-toolkit/CheckBox/index.css'

                import DATASET_URL from './DATASET_URL'

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

                class App extends React.Component {
                  constructor(props) {
                    super(props)

                    this.state = {
                      columns: [
                        { name: 'id', type: 'number', defaultWidth: 40 },
                        { name: 'firstName', flex: 1 },
                        { name: 'lastName', flex: 1 },
                        { name: 'email', groupBy: false, flex: 1 }
                      ],
                      dataSource: ({ skip, limit }) => fetch(DATASET_URL).then(response => {
                        const totalCount = response.headers.get('X-Total-Count');
                        const data = response.json();
                        return { data, count: parseInt(totalCount) };
                      }),
                      defaultUnselected: { 1: true, 3: true },
                      selected: true,
                      checkboxOnlyRowSelect: true
                    }

                    this.onSelectionChange = this.onSelectionChange.bind(this)
                  }

                  onSelectionChange({ selected, unselected }) {
                    this.setState({
                      selected,
                      unselected
                    })
                  }
                  render() {
                    const { checkboxOnlyRowSelect, selected, unselected } = this.state
                    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={(checkboxOnlyRowSelect) => this.setState({ checkboxOnlyRowSelect })}
                        >
                          Update row select using checkbox clicks only
                        </CheckBox>
                      </div>
                      <DataGrid
                        idProperty="id"
                        style={gridStyle}
                        checkboxColumn
                        columns={this.state.columns}
                        checkboxOnlyRowSelect={checkboxOnlyRowSelect}
                        pagination
                        selected={selected}
                        defaultUnselected={this.state.defaultUnselected}
                        onSelectionChange={this.onSelectionChange}
                        sortable={false}
                        dataSource={this.state.dataSource}
                      />
                    </div>
                  }
                }

                export default () => <App />
              
Bool|Function(editValue, cellProps)
default: false
Specifies whether the <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      editable: true,
      columns: [
        { name: 'id', type: 'number', editable: () => false },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          editable: (editValue) => {
            return Promise.resolve(editValue !== 'uk')
          },
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(editable) => this.setState({ editable }) }
          checked={this.state.editable}>
          Enable inline edit
        </CheckBox>
      </div>
      <p>ID column not editable.
      </p>
      <p>!!! Cells with "uk" are not editable !!!
      </p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        onEditComplete={this.onEditComplete}
        editable={this.state.editable}
        columns={this.state.columns}
        dataSource={this.state.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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      editOnSingleClick: true,
      columns: [
        { name: 'id', type: 'number', editable: () => false },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(editOnSingleClick) => this.setState({ editOnSingleClick }) }
          checked={this.state.editOnSingleClick}>
          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 {this.state.editOnSingleClick? 'click':'dblclick'}
      </p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        editStartEvent={this.state.editOnSingleClick? "click": "dblclick"}
        onEditComplete={this.onEditComplete}
        editable={true}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
React.Node|Fn()
default: "No records available"
When the <DataGrid /> has no records,emptyText), will be displayed centered inside the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const gridStyle = { minHeight: 550 }

const emptyText = <b style={{ padding: 5, border: '1px solid red'}}>No contents here !!!</b>

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: [],
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name', flex: 1, minWidth: 80 },
        { name: 'country', flex: 1, minWidth: 80 },
        { name: 'city', flex: 1, minWidth: 80 },
        { name: 'age', minWidth: 80, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        emptyText={emptyText}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: undefined
When true, makes the <DataGrid /> filterable if defaultFilterValue or filterValue is specified.
When false, it will make the <DataGrid /> unfilterable (even if defaultFilterValue or filterValue have been specified).
This is generally useful when you want to toggle filtering for an already filterable <DataGrid />.
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<DataGrid /> to respond to the change.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      enableFiltering: true,
      filterValue: [
        { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', defaultWidth: 80, type: 'number' },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(enableFiltering) => this.setState({ enableFiltering }) }
          checked={this.state.enableFiltering}>
          Enable filtering
        </CheckBox>
      </div>

      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={this.state.filterValue}
        enableFiltering={this.state.enableFiltering}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      enableKeyboardNavigation: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', minWidth: 100, flex: 1 },
        { name: 'age', minWidth: 80, type: 'number' }
      ],
      dataSource: people
    }
  }

  render() {
    const { enableKeyboardNavigation } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={enableKeyboardNavigation} onChange={(enableKeyboardNavigation) => this.setState({ enableKeyboardNavigation })}>
          Enable keyboard navigation
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultActiveIndex={2}
        enableKeyboardNavigation={enableKeyboardNavigation}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: undefined
Enables expanded rows in the <DataGrid />.
When this prop is not explicitly specified, the <DataGrid /> is expandable if one of the following is specified:expandedRows, defaultExpandedRows, renderRowDetails).
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const defaultExpandedRows = { 1: true }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableRowExpand: true,
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', defaultWidth: 150 },
        { name: 'country', defaultWidth: 150 },
        { name: 'age', type: 'number', defaultWidth: 150 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableRowExpand}
          onChange={(enableRowExpand) => this.setState({ enableRowExpand })}
        >
          Enable row expand
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        renderRowDetails={renderRowDetails}
        enableRowExpand={this.state.enableRowExpand}
        style={gridStyle}
        rowExpandHeight={400}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'age', type: 'number', flex: 1 },
        { name: 'country', flex: 1}
      ],
      dataSource: people,
      selected: undefined,
      enableSelection: true
    }
    this.onSelectionChange = this.onSelectionChange.bind(this)
  }
  onSelectionChange({ selected }) {
    this.setState({
      selected
    })
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => this.setState({ enableSelection })}
        >
          Enable selection
        </CheckBox>
      </div>
      <p>
        Selected row id: {this.state.selected === undefined ? 'none' : JSON.stringify(this.state.selected)}.
      </p>
      <DataGrid
        idProperty="id"
        enableSelection={this.state.enableSelection}
        onSelectionChange={this.onSelectionChange}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />

    </div>
  }
}

export default () => <App />
Object
default: undefined
Specifies which nodes in the <DataGrid /> (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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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' }
    ]
  }
]

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandedNodes: { 1: true, 2: true, '3/1': true },
      columns: [
        { name: 'name', flex: 1 },
        { name: 'size', defaultWidth: 120 }
      ],
      dataSource: treeData
    }
    this.onExpandedNodesChange = this.onExpandedNodesChange.bind(this)
  }
  onExpandedNodesChange({ expandedNodes }) {
    this.setState({
      expandedNodes
    })
  }

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

export default () => <App />
Object|Boolean
default: undefined
Specifies which rows in the <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandedRows: { 1: true, 2: true },
      collapsedRows: null,
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', defaultWidth: 150 },
        { name: 'country', defaultWidth: 150 },
        { name: 'age', type: 'number', defaultWidth: 150 }
      ],
      dataSource: people
    }
    this.onExpandedRowsChange = this.onExpandedRowsChange.bind(this)
  }
  onExpandedRowsChange({ expandedRows, collapsedRows }) {
    this.setState({
      expandedRows,
      collapsedRows
    })
  }
  render() {
    const { expandedRows, collapsedRows } = this.state
    return <div>
      <div>
        <Button onClick={() => {
          this.setState({
            expandedRows: true
          })
        }} style={{ marginRight: 10 }}>
          Expand all
        </Button>
        <Button onClick={() => {
          this.setState({
            expandedRows: {}
          })
        }}>
          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}
      <DataGrid
        idProperty="id"
        expandedRows={expandedRows}
        collapsedRows={collapsedRows}
        onExpandedRowsChange={this.onExpandedRowsChange}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

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

  return value
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80, groupBy: false, locked: true },
        { name: 'name', flex: 1 },
        { name: 'country', defaultWidth: 150, locked: true },
        { name: 'age', defaultWidth: 100, type: 'number' },
        { name: 'email', defaultWidth: 150, flex: 1, locked: 'end' },
      ],
      defaultGroupBy: ['country'],
      expandGroupTitle: false,
      dataSource: people
    }
  }

  render() {
    const { expandGroupTitle } = this.state
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={expandGroupTitle}
          onChange={(expandGroupTitle) => this.setState({ expandGroupTitle })}
        >
          Expand group title
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        renderGroupTitle={renderGroupTitle}
        expandGroupTitle={expandGroupTitle}
        defaultGroupBy={this.state.defaultGroupBy}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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.
DataGrid.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 <DataGrid /> 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:
DataGrid.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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

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

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      enableFiltering: true,
      filterValue: [
        { name: 'country', operator: 'europe', type: 'country', value: true },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', maxWidth: 100, type: 'number' },
        { name: 'name', flex: 1, maxWidth: 200 },
        { name: 'country',
          flex: 1,
          filterEditor: 'bool',
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

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

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      enableFiltering: true,
      filterValue: [
        { name: 'country', operator: 'europe', type: 'country', value: null },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country',
          flex: 1,
          filterEditor: 'bool',
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

const filterTypes = Object.assign({}, DataGrid.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
        }
      }
    ]
  }
})

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      enableFiltering: true,
      filterValue: [
        { name: 'country', operator: 'europe', type: 'country', value: true },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1, maxWidth: 200 },
        { name: 'country',
          flex: 1,
          filterEditor: 'bool',
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Fn({ value, filterValue, data })
default: undefined
The name for the column operator
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

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

const gridStyle = { minHeight: 550 }

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

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      enableFiltering: true,
      filterValue: [
        { name: 'country', operator: 'europe', type: 'country', value: null },
        { name: 'age', operator: 'gte', type: 'number', value: 21 }
      ],
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country',
          flex: 1,
          filterEditor: 'bool',
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        filterTypes={filterTypes}
        defaultFilterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Array[Object]
default: undefined
Specifies a filter value for the <DataGrid />. When this is specified, unless enableFiltering is false, the <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import filter from '@zippytech/react-datagrid-pro/filter'

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

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    const filterValue = [
      { name: 'name', operator: 'startsWith', type: 'string', value: 'B' },
      { name: 'age', operator: 'gte', type: 'number', value: 21 }
    ]
    this.state = {
      dataSource: filter(people, filterValue),
      filterValue,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'age', flex: 1, type: 'number' },
        { name: 'country', flex: 1, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1 }
      ]
    }

    this.onFilterValueChange = this.onFilterValueChange.bind(this)
  }
  onFilterValueChange(filterValue) {
    const dataSource = filter(people, filterValue)
    this.setState({
      dataSource,
      filterValue
    })
  }
  render() {
    return <div>
      <p>
        Current filter value: {JSON.stringify(this.state.filterValue, null, 2)}
      </p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        onFilterValueChange={this.onFilterValueChange}
        filterValue={this.state.filterValue}
        columns={this.state.columns}
        dataSource={this.state.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 />
Bool
default: true
If this is true, the <DataGrid /> 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 <DataGrid /> 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 <DataGrid /> 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<DataGrid />. 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', groupBy: false, type: 'number', defaultWidth: 50 },
        { name: 'firstName', defaultWidth: 150 },
        { name: 'lastName', defaultWidth: 150 },
        { name: 'email', groupBy: false, defaultWidth: 150 },
        {
          name: 'permissionToCall',
          defaultWidth: 200,
          render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
          renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
        }
      ],
      dataSource: ({ skip, limit, sortInfo, groupBy }) => 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');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      groupBy: []
    }

    this.onGroupByChange = this.onGroupByChange.bind(this)
  }

  onGroupByChange(groupBy) { this.groupBy(groupBy) }

  groupBy(groupBy) {
    this.setState({ groupBy })
  }

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

export default () => <App />
String
default: undefined
Specifies a group for the columns generated for grouping.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

const groups = [{name: 'permission'}]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        {
          name: 'permissionToCall',
          defaultWidth: 200,
          group: 'permission',
          render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
          renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
        },
        { name: 'id', groupBy: false, type: 'number', defaultWidth: 50 },
        { name: 'firstName', defaultWidth: 150 },
        { name: 'lastName', defaultWidth: 150 },
        { name: 'email', groupBy: false, defaultWidth: 150 }
      ],
      dataSource: ({ skip, limit, sortInfo, groupBy }) => 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');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      groupBy: ['permissionToCall']
    }

    this.onGroupByChange = this.onGroupByChange.bind(this)
  }

  onGroupByChange(groupBy) { this.groupBy(groupBy) }

  groupBy(groupBy) {
    this.setState({ groupBy })
  }

  render() {
    return <div>
      <p>In this example, you cannot group by id or email.</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        groupBy={this.state.groupBy}
        groups={groups}
        hideGroupByColumns={false}
        groupForGroupColumns="permission"
        onGroupByChange={this.onGroupByChange}
        columns={this.state.columns}
        dataSource={this.state.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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import DATASET_URL from './DATASET_URL'

const gridStyle = { minHeight: 600 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', groupBy: false, type: 'number', defaultWidth: 60 },
        { name: 'firstName', defaultWidth: 150 },
        { name: 'lastName', defaultWidth: 150 },
        { name: 'email', groupBy: false, defaultWidth: 150 },
        {
          name: 'permissionToCall', defaultWidth: 200,
          render: ({data}) => data.permissionToCall ? 'Yes' : 'No',
          renderGroupTitle: value => value ? 'Can be called' : 'Cannot be called'
        }
      ],
      dataSource: ({ skip, limit, sortInfo, groupBy }) => 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');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      groupBy: ['permissionToCall']
    }
  }

  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        groupNestingSize={100}
        defaultGroupBy={this.state.groupBy}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
default: undefined
The character to be used as group separator, when specifying the collapsed groups in a <DataGrid />.
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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 600 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', defaultWidth: 140 },
        { name: 'city', defaultWidth: 140 },
        { name: 'email', defaultWidth: 140, flex: 1 }
      ],
      groupBy: ['country','city'],
      collapsedGroups: { 'uk#London': true, 'uk#Bristol': true },
      dataSource: people
    }

    this.onGroupCollapseChange = this.onGroupCollapseChange.bind(this)
  }

  onGroupCollapseChange(collapsedGroups) {
    this.setState({
      collapsedGroups
    })
  }

  render() {
    const { collapsedGroups } = this.state
    return <div>
      <p>
        Collapsed groups: {JSON.stringify(Object.keys(collapsedGroups))}.
      </p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        collapsedGroups={collapsedGroups}
        groupPathSeparator="#"
        onGroupCollapseChange={this.onGroupCollapseChange}
        defaultGroupBy={this.state.groupBy}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Array
default: undefined
Specifies a group property to <DataGrid />.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80 },
  { name: 'firstName', group: 'personalInfo', flex: 2 },
  { name: 'age', group: 'personalInfo', type: 'number' },
  { name: 'email', group: 'contactInfo', flex: 2 },
  { name: 'phone', group: 'contactInfo' },
  { name: 'city', group: 'location' },
  { name: 'streetName', group: 'street', flex: 1 },
  { name: 'streetNo', group: 'street', type: 'number' }
]
const groups = [
  { name: 'street', group: 'location' },
  { name: 'personalInfo', group: 'details' },
  { name: 'contactInfo', group: 'details' },
  { name: 'location', group: 'details' },
  { name: 'details', header: 'Detailed info' }
]

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>
  <DataGrid
    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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 40 },
  { name: 'firstName', group: 'personalInfo', flex: 2 },
  { name: 'age', group: 'personalInfo', type: 'number', defaultWidth: 50 },
  { name: 'email', group: 'contactInfo', flex: 2 },
  { name: 'phone', group: 'contactInfo', flex: 1 },
  { name: 'city', group: 'location', flex: 1 },
  { name: 'streetName', group: 'street', flex: 1 },
  { name: 'streetNo', group: 'street', type: 'number', defaultWidth: 50 }
]
const groups = [
  { name: 'street', group: 'location' },
  { name: 'personalInfo', group: 'details' },
  { name: 'contactInfo', group: 'details' },
  { name: 'location', group: 'details', draggable: false },
  { name: 'details', header: 'Detailed info' }
]

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>
  <DataGrid
    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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 40 },
  { name: 'firstName', group: 'personalInfo', flex: 2 },
  { name: 'age', group: 'personalInfo', type: 'number', defaultWidth: 50 },
  { name: 'email', group: 'contactInfo', flex: 2 },
  { name: 'phone', group: 'contactInfo', flex: 1 },
  { name: 'city', group: 'location', flex: 1 },
  { name: 'streetName', group: 'street', flex: 1 },
  { name: 'streetNo', group: 'street', type: 'number', defaultWidth: 50 }
]
const groups = [
  { name: 'street', group: 'location' },
  { name: 'personalInfo', group: 'details' },
  { name: 'contactInfo', group: 'details' },
  { name: 'location', group: 'details' },
  { name: 'details', header: 'Detailed info' }
]

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>
  <DataGrid
    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 <DataGrid /> is smart enough to know how to split group headers and where new groups begin.
So all you need to pass to the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const columns = [
  { name: 'id', type: 'number', minWidth: 50 },
  { name: 'firstName', group: 'personalInfo', flex: 2 },
  { name: 'age', group: 'personalInfo', type: 'number', minWidth: 50 },
  { name: 'email', group: 'contactInfo', flex: 2 },
  { name: 'phone', group: 'contactInfo', flex: 1 },
  { name: 'city', group: 'location', flex: 1 },
  { name: 'streetName', group: 'street', flex: 1 },
  { name: 'streetNo', group: 'street', type: 'number', minWidth: 50 }
]

const groups = [
  { name: 'street', group: 'location' },
  { name: 'personalInfo', group: 'details', header: 'Information about you' },
  { name: 'contactInfo', group: 'details', header: <span style={{ color: 'green' }}>Contact</span> },
  { name: 'location', group: 'details', header: <span style={{ color: 'red' }}>Where you live</span> },
  { name: 'details', header: 'Detailed info' }
]

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>
  <DataGrid
    idProperty="id"
    style={gridStyle}
    columnMinWidth={100}
    columns={columns}
    groups={groups}
    dataSource={dataSource}
  />
</div>
Bool
default: true
Controls header visibility. Specify header=false to hide <DataGrid /> headers.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-datagrid-pro/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const columns = [
  { name: 'id', type: 'number', defaultWidth: 80 },
  { name: 'name', flex: 1 },
  { name: 'city', flex: 1 },
  { name: 'age', type: 'number', flex: 1 }
]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      showHeader: true
    }
  }
  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox
          checked={this.state.showHeader}
          onChange={(showHeader) => this.setState({showHeader})}
        >
          Show header
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        columns={columns}
        dataSource={people}
        header={this.state.showHeader}
      />
    </div>
  }
}
export default () => <App />
Object
default: undefined
If specified, this object will be passed to the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }
const headerProps = {
  style: {
    height: 120,
    background: 'tomato',
    color: 'white'
  }
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        headerProps={headerProps}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Specifies whether the columns used for grouping should be hidden or not.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'country', flex: 1 },
        { name: 'firstName', flex: 1 },
        { name: 'age', type: 'number', flex: 1 }
      ],
      dataSource: people,
      hideGroupByColumns: true,
      groupBy: ['country']
    }
  }

  render() {
    const { hideGroupByColumns } = this.state
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={hideGroupByColumns}
          onChange={(hideGroupByColumns) => this.setState({ hideGroupByColumns })}
        >
          Hide group by columns
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultGroupBy={this.state.groupBy}
        hideGroupByColumns={hideGroupByColumns}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
This is an object you can use to translate/internationalize labels/text content used in the <DataGrid />.
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'
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const columns = [
  { name: 'name', flex: 1 },
  { name: 'age', flex: 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({}, DataGrid.defaultProps.i18n, {
  sortAsc: 'Execute ASC sort',
  sortDesc: 'Execute DESC sort',
  clear: 'Remove',
  clearAll: 'Remove All'
})

export default () => <div>
  <DataGrid
    i18n={i18n}
    columns={columns}
    dataSource={dataSource}
    style={gridStyle}
  />
</div>
String
default: "id"
The simplest dataSource is an array of objects, with properties matching the names of the <DataGrid /> 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 <DataGrid /> rows. This identifier property name should be used as the idProperty to help uniquely identify <DataGrid /> rows.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const columns = [
  { name: 'name', flex: 1 },
  { name: 'age', flex: 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>
  <DataGrid
    idProperty="uniqueId"
    columns={columns}
    dataSource={dataSource}
    style={gridStyle}
  />
</div>
Fn(info)
default: undefined
By default, rows/nodes/groups are collapsed when Alt+ArrowLeft is pressed. The default implementation of this function is ({event}) => event.key === 'ArrowLeft' && event.altKey;
By providing a different implementation, you can change the key combination on which rows/nodes/groups are collapsed.
See related isExpandKeyPressed
The info param has an event property and also many properties with information about the currently active row:
  • event - the event object
  • data - the current active row. An alias of activeItem
  • index - the current active index. An alias of activeIndex
  • activeItem - the current active row
  • activeIndex - the current active index
  • grid - a reference to the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

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>
    <h3>Row details:</h3>
    <table>
      {Object.keys(data).map(name => {
        return <tr key={name}>
          <td>{name}</td>
          <td>{data[name]}</td>
        </tr>
      })}
    </table>
  </div>
}

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 30 },
        { name: 'name', defaultWidth: 450 },
        { name: 'country', defaultWidth: 450 },
        { name: 'age', type: 'number', defaultWidth: 450 }
      ],
      dataSource: people
    }
  }
  render() {

    return <div>
      <p>
        Use Shift + Arrow keys to expand/collapse rows.
      </p>
      <DataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        isExpandKeyPressed={isExpandKeyPressed}
        isCollapseKeyPressed={isCollapseKeyPressed}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

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>
    <h3>Row details:</h3>
    <table>
      {Object.keys(data).map(name => {
        return <tr key={name}>
          <td>{name}</td>
          <td>{data[name]}</td>
        </tr>
      })}
    </table>
  </div>
}

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 30 },
        { name: 'name', defaultWidth: 450 },
        { name: 'country', defaultWidth: 450 },
        { name: 'age', type: 'number', defaultWidth: 450 }
      ],
      dataSource: people
    }
  }
  render() {

    return <div>
      <p>
        Use Shift + Arrow keys to expand/collapse rows.
      </p>
      <DataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        isExpandKeyPressed={isExpandKeyPressed}
        isCollapseKeyPressed={isCollapseKeyPressed}
        style={gridStyle}
        rowExpandHeight={400}
        renderRowDetails={renderRowDetails}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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', flex: 1 },
  { name: 'size', defaultWidth: 120 }
]

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
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      treeColumn: 'name'
    }
  }
  render() {
    const { treeColumn } = this.state

    return <div>
      <div style={{ marginBottom: 20 }}>
        <p>DataGrid with the "Applications" node forced to async</p>
      </div>
      <DataGrid
        isNodeAsync={isNodeAsync}
        loadNode={loadNode}
        defaultExpandedNodes={defaultExpandedNodes}
        treeColumn={treeColumn}
        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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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', flex: 1 },
  { name: 'size', defaultWidth: 120 }
]

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
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      treeColumn: 'name'
    }
  }
  render() {
    const { treeColumn } = this.state

    return <div>
      <div style={{ marginBottom: 20 }}>
        <p>DataGrid with the "Applications" node forced to be a leaf</p>
      </div>
      <DataGrid
        isNodeLeaf={isNodeLeaf}
        loadNode={loadNode}
        defaultExpandedNodes={defaultExpandedNodes}
        treeColumn={treeColumn}
        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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', defaultWidth: 150 },
        { name: 'country', defaultWidth: 150 },
        { name: 'age', type: 'number', defaultWidth: 150 }
      ],
      dataSource: people
    }

    this.isRowExpandable = this.isRowExpandable.bind(this)
  }
  isRowExpandable({ data }) {
    return data.age >= 30
  }
  render() {
    return <DataGrid
      idProperty="id"
      isRowExpandable={this.isRowExpandable}
      style={gridStyle}
      rowExpandHeight={400}
      renderRowDetails={renderRowDetails}
      columns={this.state.columns}
      dataSource={this.state.dataSource}
    />
  }
}

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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

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

const gridStyle = { minHeight: 550 }

const isStartEditKeyPressed = ({ event }) => event.key === 'g' && event.ctrlKey

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', minWidth: 300, type: 'number' },
        { name: 'name', flex: 1, minWidth: 400 },
        { name: 'country', flex: 1, minWidth: 400, render: ({ value })=> flags[value]? <img src={flags[value]} />: value },
        { name: 'city', flex: 1, minWidth: 400 },
        { name: 'age', minWidth: 350, type: 'number' }
      ]
    }

    this.onEditComplete = this.onEditComplete.bind(this)
  }
  onEditComplete({ value, columnId, rowIndex }) {
    console.log(value, columnId, rowIndex)
    const dataSource = [...this.state.dataSource];
    dataSource[rowIndex][columnId] = value;

    this.setState({
      dataSource
    });
  }
  render() {
    return <div>
      <h3>Trigger inline edit via a custom keyboard shortcut: Ctrl+G</h3>
      <DataGrid
        isStartEditKeyPressed={isStartEditKeyPressed}
        idProperty="id"
        style={gridStyle}
        onEditComplete={this.onEditComplete}
        editable={true}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: 10
When the user navigates the <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'firstName', flex: 1 },
        { name: 'country', defaultWidth: 100 },
        { name: 'age', defaultWidth: 100, type: 'number' },
        {
          id: 'desc',
          header: 'Description',
          defaultWidth: 250,
          render: ({ data}) => data.firstName + ', aged: ' + data.age + '. Lives in ' + data.country
        }
      ],
      lastKey: null,
      dataSource: people
    }
  }
  render() {
    return <div>
      <p>Focus the grid and press PageDown/PageUp to navigate by 4 rows downwards/upwards!</p>
      <DataGrid
        idProperty="id"
        keyPageStep={4}
        defaultActiveIndex={6}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: 50
The page size for the <DataGrid />, 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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, sortInfo }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+this.state.limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      limit: 10
    }

    this.onLimitChange = this.onLimitChange.bind(this)
  }

  onLimitChange(limit) {
    this.setState({ limit })
  }

  render() {
    return <div>
      <p>Try to update the page size in the combo to see the limit change</p>
      <p>Current limit (page size): {this.state.limit}.</p>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        pagination
        pageSizes={this.state.pageSizes}
        onLimitChange={this.onLimitChange}
        dataSource={this.state.dataSource}
        limit={this.state.limit}
      />
    </div>
  }
}
export default () => <App />
Bool
default: undefined
Specifies that the <DataGrid /> should use live pagination
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      livePagination: true,
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+limit).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      })
    }
  }

  render() {
    const { livePagination } = this.state
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        livePagination={livePagination}
        pagination
        sortable={false}
        dataSource={this.state.dataSource}
        limit={15}
      />
    </div>
  }
}

export default () => <App />
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 <DataGrid />. If you are using the controlled loading, you need to make sure the loading mask is displayed while fetching remote data.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      loading: false,
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', defaultWidth: 150, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <div style={{marginBottom: 20}}>
        <CheckBox checked={this.state.loading} onChange={(loading) => this.setState({ loading })}>
          Show load mask
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        loading={this.state.loading}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'

const gridStyle = { minHeight: 550 }

const pleaseWait = <b>Please wait while loading ... </b>

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: [],
      columns: [
        { name: 'id', type: 'number', defaultWidth: 60 },
        { name: 'name', flex: 1, defaultWidth: 100 },
        { name: 'country', flex: 1, defaultWidth: 100 },
        { name: 'city', flex: 1, defaultWidth: 100 },
        { name: 'age', defaultWidth: 150, type: 'number' }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        loading={true}
        loadingText={pleaseWait}
        columns={this.state.columns}
        dataSource={this.state.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.
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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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', flex: 1 },
  { name: 'size', defaultWidth: 120 }
]

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 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      treeNestingSize: 22
    }
  }
  render() {

    return <div>
      <h3>TreeGrid with async nodes</h3>
      <DataGrid
        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.
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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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', flex: 1 },
  { name: 'size', defaultWidth: 120 }
]

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 }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      treeNestingSize: 22
    }
  }
  render() {

    return <div>
      <h3>TreeGrid with async nodes</h3>
      <DataGrid
        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
Number
default: undefined
Should only be used when the <DataGrid /> is configured to have dynamic row height (rowHeight=null). In this situation, the <DataGrid /> needs a minimum height for rows - configured via the mandatory minRowHeight prop.
Since minRowHeight is used when the<DataGrid /> 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 <DataGrid /> cells (and not rows), which dictate the height of <DataGrid /> rows.
The natural DOM height of <DataGrid /> 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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import people from './people'

const gridStyle = { minHeight: 550 }

const bigCellStyle = {
  minHeight: 80,
  display: 'flex',
  alignItems: 'center'
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number' },
        { name: 'name', flex: 2, render: ({ rowIndex }) => rowIndex % 2 ? <div style={bigCellStyle}>big cell</div> : 'this has minHeight' },
        { name: 'age', type: 'number', flex: 1 }
      ]
    }
  }
  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        minRowHeight={50}
        rowHeight={null}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const defaultExpandedRows = { 1: true }

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

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      multiRowExpand: true,
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', defaultWidth: 150 },
        { name: 'country', defaultWidth: 150 },
        { name: 'age', type: 'number', defaultWidth: 150 }
      ],
      dataSource: people
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.multiRowExpand}
          onChange={(multiRowExpand) => this.setState({ multiRowExpand })}
        >
          Multi row expand
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        defaultExpandedRows={defaultExpandedRows}
        renderRowDetails={renderRowDetails}
        multiRowExpand={this.state.multiRowExpand}
        style={gridStyle}
        rowExpandHeight={400}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: undefined
Enables or disabled multiple cellSelection. Cell selection is multiple selection by default.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      columns: [
        { name: 'id', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ],
      multiSelect: true,
      dataSource: people
    }
  }
  render() {
    const { multiSelect } = this.state
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={multiSelect} onChange={(multiSelect) => this.setState({ multiSelect }) }>
          Enable multiSelect - applies for cells
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        multiSelect={multiSelect}
        defaultCellSelection={[]}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
If true, native browser scrollbars will be used instead of the default custom scrollbars of the DataGrid.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 300 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1 },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ],
      autoHide: false,
      alwaysShowTrack: false,
      redBackground: false,
      customSize: false,
      customRadius: false,
      nativeScroll: false
    }
  }
  render() {
    const scrollProps = Object.assign({}, DataGrid.defaultProps.scrollProps, {
      autoHide: this.state.autoHide,
      alwaysShowTrack: this.state.alwaysShowTrack
    })

    if (this.state.customSize) {
      scrollProps.scrollThumbWidth = 15
      scrollProps.scrollThumbOverWidth = 20
    }
    if (this.state.customRadius) {
      scrollProps.scrollThumbRadius = 20
    }
    if (this.state.redBackground) {
      scrollProps.scrollThumbStyle = {
        background: '#ff7474'
      }
    }

    const nativeScroll = this.state.nativeScroll

    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={nativeScroll}
          onChange={(nativeScroll) => {
            this.setState({
              nativeScroll
            })
          }}
        >
          Use native scroll
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && this.state.autoHide}
          onChange={(autoHide) => {
            this.setState({
              autoHide
            })
          }}
        >
          Auto-hide scrollbars
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && this.state.alwaysShowTrack}
          onChange={(alwaysShowTrack) => {
            this.setState({
              alwaysShowTrack
            })
          }}
        >
          Always show track
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && this.state.redBackground}
          onChange={(redBackground) => {
            this.setState({
              redBackground
            })
          }}
        >
          Red background for scroll thumbs
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && this.state.customSize}
          onChange={(customSize) => {
            this.setState({
              customSize
            })
          }}
        >
          Custom scrollbar size
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          disabled={nativeScroll}
          checked={!nativeScroll && this.state.customRadius}
          onChange={(customRadius) => {
            this.setState({
              customRadius
            })
          }}
        >
          Custom radius (20px)
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        scrollProps={scrollProps}
        nativeScroll={this.state.nativeScroll}
        columns={this.state.columns}
        enableKeyboardNavigation={false}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
String
default: "/"
The character to be used as node path separator - the <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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' }
    ]
  }
]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      expandedNodes: { 3: true, '3#1': true },
      columns: [
        { name: 'name', flex: 1 },
        { name: 'size', defaultWidth: 120 }
      ],
      dataSource: treeData
    }

    this.onExpandedNodesChange = this.onExpandedNodesChange.bind(this)
  }

  onExpandedNodesChange({ expandedNodes }) {
    this.setState({
      expandedNodes
    })
  }

  render() {
    const { expandedNodes } = this.state
    return <div>
      <p>
        Expanded nodes: {expandedNodes == null ? 'none' : JSON.stringify(expandedNodes, null, 2)}.
      </p>
      <DataGrid
        treeColumn="name"
        expandedNodes={expandedNodes}
        nodePathSeparator="#"
        onExpandedNodesChange={this.onExpandedNodesChange}
        style={gridStyle}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
        />
    </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 DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/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', flex: 1 },
  { name: 'size', defaultWidth: 120 }
]

const defaultExpandedNodes = { 1: true }

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      treeColumn: 'name'
    }
  }
  render() {
    const { treeColumn } = this.state

    return <div>
      <div style={{ marginBottom: 20 }}>
        <p>DataGrid with nodes in "items" prop of each node</p>
      </div>
      <DataGrid
        nodesProperty="items"
        defaultExpandedNodes={defaultExpandedNodes}
        treeColumn={treeColumn}
        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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit, sortInfo }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      pageSizes: [5, 10, 20, 40, 80]
    }
  }

  render() {
    return <div>
      <DataGrid idProperty="id" style={gridStyle}
        columns={this.state.columns}
        pagination
        defaultLimit={10}
        pageSizes={this.state.pageSizes}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Boolean|String
default: undefined
Configured pagination for the <DataGrid /> - 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 <DataGrid /> 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 from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit, sortInfo }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      })
    }
  }

  render() {
    return <div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        columns={this.state.columns}
        pagination
        sortable={false}
        dataSource={this.state.dataSource}
        defaultLimit={10}
      />
    </div>
  }
}

export default () => <App />
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 <DataGrid />.
  • skip - used to control skip value for the <DataGrid />.
  • defaultLimit - used to configure the default page size for the <DataGrid />.
  • defaultSkip - used to control the default skip value for the <DataGrid />.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import DATASET_URL from './DATASET_URL'

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

const empty = () => null

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: 'id', type: 'number', maxWidth: 40 },
        { name: 'firstName', flex: 1 },
        { name: 'lastName', flex: 1 },
        { name: 'email', groupBy: false, flex: 1 }
      ],
      dataSource: ({ skip, limit, sortInfo }) => fetch(DATASET_URL + '?skip='+skip + '&limit='+limit+(sortInfo ? '&sortInfo='+JSON.stringify(sortInfo) : '')).then(response => {
        const totalCount = response.headers.get('X-Total-Count');
        const data = response.json();
        return { data, count: parseInt(totalCount) };
      }),
      skip: 10,
      limit: 10,
      sortInfo: null
    }

    this.onSortInfoChange = this.onSortInfoChange.bind(this)
    this.onLimitChange = this.onLimitChange.bind(this)
    this.onSkipChange = this.onSkipChange.bind(this)
  }

  onSkipChange(skip) {
    this.setState({ skip })
  }
  onLimitChange(limit) {
    this.setState({ limit })
  }
  updateSkip(amount) {
    return () => {
      let skip = this.state.skip + amount
      skip = Math.min(skip, 100)
      skip = Math.max(skip, 0)

      this.setState({
        skip
      })
    }
  }
  updateLimit(amount) {
    return () => {
      let limit = this.state.limit + amount
      limit = Math.min(limit, 100)
      limit = Math.max(limit, 0)

      this.setState({
        limit
      })
    }
  }
  onSortInfoChange(sortInfo) {
    this.setState({
      sortInfo
    })
  }
  sortBy(colName, dir) {
    return () => {
      this.setState({
        sortInfo: {
          name: colName,
          dir
        }
      })
    }
  }

  render() {
    const disabled = this.state.loading || Array.isArray(this.state.dataSource)

    return <div>
      <p>Current skip: {this.state.skip}. Current limit: {this.state.limit}.</p>
      <p className="global-datagrid-children-margin">
        <Button onClick={this.updateSkip(10)} disabled={disabled}>skip += 10</Button>
        <Button onClick={this.updateSkip(-10)} disabled={disabled || this.state.skip==0}>skip -= 10</Button>
        <Button onClick={this.updateLimit(10)} disabled={disabled}>limit += 10</Button>
        <Button onClick={this.updateLimit(-10)} disabled={disabled  || this.state.limit<=10}>limit -= 10</Button>
        <Button onClick={this.sortBy("firstName", 1)} disabled={disabled}>sort by First Name, ASC</Button>
        <Button onClick={this.sortBy("lastName", -1)} disabled={disabled}>sort by Last Name, DESC</Button>
      </p>
      <DataGrid idProperty="id" style={gridStyle}
        columns={this.state.columns}
        sortInfo={this.state.sortInfo}
        onSortInfoChange={this.onSortInfoChange}
        pagination limit={this.state.limit} skip={this.state.skip}
        onLimitChange={this.onLimitChange}
        onSkipChange={this.onSkipChange}
        renderPaginationToolbar={empty}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
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 <DataGrid /> rows.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import people from './people'

const gridStyle = { minHeight: 550 }

const defaultSelected={}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      preventDefaultTextSelectionOnShiftMouseDown: true,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', header: 'Name - try selecting text in cells', flex: 1, minWidth: 250, },
        { name: 'age', flex: 1, minWidth: 250, header: 'Cells in this col are always selectable - userSelect: true', userSelect: true }
      ],
      dataSource: people
    }
  }

  render() {
    const { preventDefaultTextSelectionOnShiftMouseDown } = this.state
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox checked={preventDefaultTextSelectionOnShiftMouseDown} onChange={(preventDefaultTextSelectionOnShiftMouseDown) => this.setState({ preventDefaultTextSelectionOnShiftMouseDown })}>
        Prevent default text selection on shift + mouseDown
        </CheckBox>
      </div>
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultSelected={defaultSelected}
        enableSelection
        columnUserSelect
        preventDefaultTextSelectionOnShiftMouseDown={preventDefaultTextSelectionOnShiftMouseDown}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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 <DataGrid /> and grid is a reference to the <DataGrid /> instance.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import NotificationBoard from '@zippytech/react-toolkit/Notification'
import '@zippytech/react-toolkit/Notification/index.css'

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

const gridStyle = { minHeight: 600 }

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.renderColumnContextMenu = this.renderColumnContextMenu.bind(this)
  }

  renderColumnContextMenu(menuProps, { cellProps }) {
    menuProps.items = menuProps.items.concat([
      {
        label: 'Custom item for "' + cellProps.name + '"',
        onClick: () => {
          zippy.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Column context menu item clicked'
          })
        }
      },
      {
        label: 'Another custom menu item',
        onClick: () => {
          zippy.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Second custom column context menu item clicked!!!'
          })
        }
      }
    ])
  }

  render() {
    return <div>
      <NotificationBoard id="first" />
      <DataGrid
        idProperty="id"
        style={gridStyle}
        renderColumnContextMenu={this.renderColumnContextMenu}
        columns={this.state.columns}
        dataSource={this.state.dataSource}
      />
    </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 <DataGrid /> 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 <DataGrid /> and grid is a reference to the <DataGrid /> instance.
import React from 'react'
import DataGrid from '@zippytech/react-datagrid-pro'
import '@zippytech/react-datagrid-pro/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'
import NotificationBoard from '@zippytech/react-toolkit/Notification'
import '@zippytech/react-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' }
]

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: people,
      columns: [
        { name: 'id', type: 'number', defaultWidth: 80 },
        { name: 'name', flex: 1 },
        { name: 'country', flex: 1,
          render: ({ value })=> flags[value]? <img src={flags[value]} />: value
        },
        { name: 'city', flex: 1 },
        { name: 'age', flex: 1, type: 'number' }
      ]
    }

    this.renderColumnFilterContextMenu = this.renderColumnFilterContextMenu.bind(this)
  }

  renderColumnFilterContextMenu(menuProps, { cellProps }) {
    menuProps.items = menuProps.items.concat([
      {
        label: 'Custom filter item for "' + cellProps.name + '"',
        onClick: () => {
          zippy.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Column context menu item clicked'
          })
        }
      },
      {
        label: 'Another custom filter item',
        onClick: () => {
          zippy.notification.first.addNotification({
            title: 'Custom notification for column ' + cellProps.name,
            content: 'Second custom column context menu item clicked!!!'
          })
        }
      }
    ])
  }

  render() {
    return <div>
      <NotificationBoard id="first" />
      <DataGrid
        idProperty="id"
        style={gridStyle}
        defaultFilterValue={defaultFilterValue}
        renderColumnFilterContextMenu={this.renderColumnFilterContextMenu}
        columns={this.state.columns}