Cell Selection

To use multi-cell selection, you need to configure the <DataSource /> component with selectionMode="multi-cell" - see selectionMode for details. For selecting rows, see the Row Selection page.

Configuring the selection mode
<DataSource selectionMode="multi-cell" />

// can be "single-row", "multi-row", "multi-cell" or false
Multiple cell selection example

Click cells in the grid to add to the selection.

Use Shift+Click to select a range of cells and Cmd/Ctrl+Click to add single cells to the selection.

View Mode
Fork
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
} from '@infinite-table/infinite-react';

import * as React from 'react';

type Developer = {
  id: number;
  firstName: string;
  lastName: string;
  country: string;
  city: string;
  currency: string;
  preferredLanguage: string;
  stack: string;
  canDesign: 'yes' | 'no';
  hobby: string;
  salary: number;
  age: number;
};

const dataSource = () => {
  return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  id: { field: 'id', defaultWidth: 60 },
  firstName: { field: 'firstName' },
  preferredLanguage: { field: 'preferredLanguage' },
  stack: { field: 'stack' },
  country: { field: 'country' },
  age: { field: 'age', type: 'number' },
  salary: { field: 'salary', type: 'number' },
  currency: { field: 'currency', type: 'number' },
};

export default function App() {
  return (
    <DataSource<Developer>
      primaryKey="id"
      data={dataSource}
      selectionMode="multi-cell"
    >
      <InfiniteTable<Developer> columns={columns} columnDefaultWidth={100} />
    </DataSource>
  );
}

Using default selection

You can specify a default value for cell selection by using the defaultCellSelection prop.

Using default selection

const defaultCellSelection = {
  defaultSelection: false,
  selectedCells: [
    [3, "stack"], // rowId + colId
    [5, "stack"], // rowId + colId
    [0, "firstName"], // rowId + colId
  ]
}

<DataSource
  selectionMode="multi-cell"
  defaultCellSelection={defaultCellSelection}

Note

Cell selection uses [rowId, colId] cell descriptors to identify cells to be marked as selected or deselected - read more in the Cell selection format.

Multiple cell selection with a default selection value

By default some cells are already selected in the grid below, by using the defaultCellSelection prop on the <DataSource /> component.

View Mode
Fork
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
  DataSourcePropCellSelection_MultiCell,
} from '@infinite-table/infinite-react';

import * as React from 'react';

type Developer = {
  id: number;
  firstName: string;
  lastName: string;
  country: string;
  city: string;
  currency: string;
  preferredLanguage: string;
  stack: string;
  canDesign: 'yes' | 'no';
  hobby: string;
  salary: number;
  age: number;
};

const dataSource = () => {
  return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  id: { field: 'id', defaultWidth: 60 },
  firstName: { field: 'firstName' },
  preferredLanguage: { field: 'preferredLanguage' },
  stack: { field: 'stack' },
  country: { field: 'country' },
  age: { field: 'age', type: 'number' },
  salary: { field: 'salary', type: 'number' },
  currency: { field: 'currency', type: 'number' },
};

export default function App() {
  const defaultCellSelection: DataSourcePropCellSelection_MultiCell = {
    defaultSelection: false,
    selectedCells: [
      [3, 'stack'], // rowId + colId
      [4, 'stack'],
      [5, 'stack'],
      [0, 'firstName'],
    ],
  };
  return (
    <DataSource<Developer>
      primaryKey="id"
      data={dataSource}
      defaultCellSelection={defaultCellSelection}
      selectionMode="multi-cell"
    >
      <InfiniteTable<Developer> columns={columns} columnDefaultWidth={100} />
    </DataSource>
  );
}

Whe you're using cell selection with or without any default value (via the defaultCellSelection), you're using an uncontrolled prop. This means that the selection state is managed by the <DataSource /> component and not by you. If you want to control the selection state yourself, you can use the controlled cellSelection prop instead - see Using controlled selection for details.

Cell selection format

The cellSelection prop is an object with the following shape:

  • defaultSelection - boolean - whether or not cells are selected by default.
  • either:
    • selectedCells: [rowId, colId][] - an array of cells that should be selected (this is combined with defaultSelection: false)
  • or
    • deselectedCells: [rowId, colId][] - an array of cells that should be deselected (this is combined with defaultSelection: true)

Note

When defaultSelection is true, you will only need to specify the deselectedCells prop.

And when defaultSelection is false, you will only need to specify the selectedCells prop.

In this way, you can either specify which cells should be selected or which cells should be deselected - and have a default that matches the most common case.

Note

The selectedCells/deselectedCells are arrays of [rowId, colId] tuples. The rowId is the id of the row (the primary key), and the colId is the id of the column (the identifier of the column in the columns prop).

The following scenarios are all possible:

Just a few specified cells are selected
const defaultCellSelection = {
  defaultSelection: false,
  selectedCells: [
    ['id2', 'stack'],
    ['id2', 'stack'],
    ['id0', 'firstName'],
  ],
}
Everything is selected, except a few cells
const defaultCellSelection = {
  defaultSelection: true,
  deselectedCells: [
    ['row2', 'stack'],
    ['row3', 'stack'],
    ['row5', 'firstName'],
  ],
}

Using wildcards for selection

It's also possible to use wildcards for selecting cells. This is useful if you want to select all cells in a column, or all cells in a row.

Selecting all cells in a column
const defaultCellSelection = {
  defaultSelection: false,
  selectedCells: [
    ['*', 'stack'],
    ['row2','firstName']
  ],
}
Selecting all cells in a row
const defaultCellSelection = {
  defaultSelection: false,
  selectedCells: [
    ['row1', '*'],
    ['row2','firstName']
  ],
}
Selecting everything except a column
const defaultCellSelection = {
  defaultSelection: true,
  deselectedCells: [
    ['*', 'stack'],
  ],
}

Using controlled selection

When using the controlled cellSelection you have to update the value of the property yourself, by listening to the onCellSelectionChange event.

Using controlled cell selection

This example shows how to use the onCellSelectionChange callback prop to listen to changes to the controlled cellSelection prop on the <DataSource /> component.

View Mode
Fork
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
  DataSourcePropCellSelection_MultiCell,
} from '@infinite-table/infinite-react';

import * as React from 'react';

type Developer = {
  id: number;
  firstName: string;
  lastName: string;
  country: string;
  city: string;
  currency: string;
  preferredLanguage: string;
  stack: string;
  canDesign: 'yes' | 'no';
  hobby: string;
  salary: number;
  age: number;
};

const dataSource = () => {
  return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  id: { field: 'id', defaultWidth: 60 },
  firstName: { field: 'firstName' },
  preferredLanguage: { field: 'preferredLanguage' },
  stack: { field: 'stack' },
  country: { field: 'country' },
  age: { field: 'age', type: 'number' },
  salary: { field: 'salary', type: 'number' },
  currency: { field: 'currency', type: 'number' },
};

export default function App() {
  const [cellSelection, setCellSelection] =
    React.useState<DataSourcePropCellSelection_MultiCell>({
      defaultSelection: false,
      selectedCells: [
        [3, 'stack'],
        [0, 'firstName'],
      ],
    });

  return (
    <div
      style={{
        display: 'flex',
        flex: 1,
        color: 'var(--infinite-cell-color)',
        flexFlow: 'column',
        background: 'var(--infinite-background)',
      }}
    >
      <div
        style={{
          maxHeight: 200,
          overflow: 'auto',
          border: '2px solid magenta',
        }}
      >
        Current selection:
        <pre>{JSON.stringify(cellSelection, null, 2)}</pre>
      </div>

      <DataSource<Developer>
        primaryKey="id"
        data={dataSource}
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        selectionMode="multi-cell"
      >
        <InfiniteTable<Developer> columns={columns} columnDefaultWidth={100} />
      </DataSource>
    </div>

Using the Cell Selection API

The <DataSource /> component also exposes a Cell Selection API, which you can use to select and deselect cells programmatically.

Using the CellSelectionAPI to select a column
View Mode
Fork
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
  DataSourcePropCellSelection_MultiCell,
  InfiniteTableApi,
} from '@infinite-table/infinite-react';

import * as React from 'react';

type Developer = {
  id: number;
  firstName: string;
  lastName: string;
  country: string;
  city: string;
  currency: string;
  preferredLanguage: string;
  stack: string;
  canDesign: 'yes' | 'no';
  hobby: string;
  salary: number;
  age: number;
};

const dataSource = () => {
  return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  id: { field: 'id', defaultWidth: 60 },
  firstName: { field: 'firstName' },
  preferredLanguage: { field: 'preferredLanguage' },
  stack: { field: 'stack' },
  country: { field: 'country' },
  age: { field: 'age', type: 'number' },
  salary: { field: 'salary', type: 'number' },
  currency: { field: 'currency', type: 'number' },
};

export default function App() {
  const [cellSelection, setCellSelection] =
    React.useState<DataSourcePropCellSelection_MultiCell>({
      defaultSelection: false,
      selectedCells: [
        [3, 'stack'],
        [0, 'firstName'],
      ],
    });

  const [api, setApi] = React.useState<InfiniteTableApi<Developer> | null>();

  return (
    <div
      style={{
        display: 'flex',
        flex: 1,
        color: 'var(--infinite-cell-color)',
        flexFlow: 'column',
        background: 'var(--infinite-background)',
      }}
    >
      <button
        style={{
          margin: 10,
          padding: 10,
          borderRadius: 5,
          border: '2px solid magenta',
        }}
        onClick={() => {
          api?.cellSelectionApi.selectColumn('firstName');
        }}
      >
        Select "firstName" column
      </button>
      <div
        style={{
          maxHeight: 200,
          overflow: 'auto',
          border: '2px solid magenta',
        }}
      >
        Current selection:
        <pre>{JSON.stringify(cellSelection, null, 2)}</pre>
      </div>

      <DataSource<Developer>
        primaryKey="id"
        data={dataSource}
        cellSelection={cellSelection}
        onCellSelectionChange={setCellSelection}
        selectionMode="multi-cell"
      >
        <InfiniteTable<Developer>
          columns={columns}
          columnDefaultWidth={100}
          onReady={({ api }) => {
            setApi(api);
          }}
        />
      </DataSource>
    </div>