# Infinite Table Cell Selection API

Canonical page: https://infinite-table.com/docs/reference/cell-selection-api/

```tsx title="Configuring the selection mode to be 'multi-cell'"
<DataSource selectionMode="multi-cell" />

// can be "single-row", "multi-row", "multi-cell" or false
```

To enable cell selection, you need to specify [selectionMode="multi-cell"](https://infinite-table.com/docs/reference/datasource-props/index.md#selectionMode) on the `<DataSource />` component.

You can retrieve the cell selection api by reading it from the `api.cellSelectionApi` property.

```tsx {4}

const onReady = ({api}: {api:InfiniteTableApi<DATA_TYPE>}) => {
  // do something with it
  api.cellSelectionApi.selectGroupRow(['USA'])
}

<InfiniteTable<DATA_TYPE>
  columns={[...]}
  onReady={onReady}
/>
```

See the [Infinite Table API page](https://infinite-table.com/docs/reference/api/index.md) for the main API.
See the [Infinite Table Keyboard Navigation API page](https://infinite-table.com/docs/reference/keyboard-navigation-api/index.md) for the keyboard navigation API.
See the [Infinite Table Row Selection API page](https://infinite-table.com/docs/reference/row-selection-api/index.md) for the row selection API.
See the [Infinite Table Column API page](https://infinite-table.com/docs/reference/column-api/index.md) for the column API.

### isCellSelected (`({rowIndex/rowId, colIndex/colId}) => boolean`)

> Boolean getter to report if a cell is selected.

The accepted argument is an object with the following properties:

- `rowIndex` (the index of the row) or `rowId` (the id of the row)
- `colIndex` (the index of the column) or `colId` (the id of the column)

You can identify the cell by any of the valid combinations of `rowIndex`/`rowId` and `colIndex`/`colId`.

Using row and column indexes for selection is supported to make it easier to use the API, but in fact cells are selected by the `rowId/colId` combination.

This is important to keep in mind, as when columns are reordered or rows are sorted/filtered - the selection will be bound to the `rowId/colId` - so cells that were selected as siblings before a column reorder might not be siblings after the reorder, but they will still be rendered as selected.

### mapCellSelectionPositions (`(fn: (rowInfo, colId) => any, emptyValue)`)

> Maps the selected cells using the passed fn.

This allows you to retrieve the values from the selected cells, by using a mapping function, so for each value (cell) in the selection, the passed `fn` is called, so you can return your own object with the values you need.

**Example: Retrieving cell selection value by mapping over them**

```ts file=cell-selection-mapping-example.page.tsx"

```

### selectColumn (`(colId: string)=> void`)

> Selects all cells in the specified column.

**Example: Using `selectColumn` with controlled selection**

```ts
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(process.env.NEXT_PUBLIC_BASE_URL + '/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>
          debugId="controlled-cell-selection-with-api-example"
          columns={columns}
          columnDefaultWidth={100}
          onReady={({ api }) => {
            setApi(api);
          }}
        />
      </DataSource>
    </div>
  );
}
```

### selectCell (`({ rowIndex/rowId, colIndex/colId, clear?: boolean}) => void`)

> Selects the specified cell.

For the shape of the argument see related [isCellSelected](#isCellSelected).

Additionally, you can pass a `clear` property to clear the selection before selecting the cell.

Also see related [deselectCell](#deselectCell).

In order to select a cell via mouse interaction, simply click the desired cell. Clicking a cell without any modifier keys will clear the selection and select the clicked cell.

You can use `Cmd/Ctrl+Click` to add cells to the selection, or `Shift+Click` to select a range of cells.

**Example: Selecting a cell via the Cell Selection API**

```ts
import {
  InfiniteTable,
  DataSource,
  InfiniteTableApi,
  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(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  id: { field: 'id' },
  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 [api, setApi] = React.useState<InfiniteTableApi<Developer> | null>(
    null,
  );
  return (
    <>
      <div
        style={{
          color: 'var(--infinite-cell-color)',
          background: 'var(--infinite-background)',
        }}
      >
        <button
          style={{
            margin: 10,
            padding: 10,
            borderRadius: 5,
            border: '2px solid magenta',
          }}
          onClick={() => {
            api?.cellSelectionApi.selectCell({
              rowIndex: 1,
              colIndex: 1,
              clear: true,
            });
          }}
        >
          Clear & Select row 1, col 1
        </button>
        <button
          style={{
            margin: 10,
            padding: 10,
            borderRadius: 5,
            border: '2px solid magenta',
          }}
          onClick={() => {
            api?.cellSelectionApi.selectCell({
              rowIndex: 1,
              colId: 'preferredLanguage',
            });
          }}
        >
          Add row 1, col `preferredLanguage` to selection
        </button>
      </div>

      <DataSource<Developer>
        primaryKey="id"
        data={dataSource}
        selectionMode="multi-cell"
      >
        <InfiniteTable<Developer>
          debugId="select-cell-example"
          onReady={({ api }) => {
            setApi(api);
          }}
          columns={columns}
          columnDefaultWidth={100}
        />
      </DataSource>
    </>
  );
}
```

### deselectCell (`({ rowIndex/rowId, colIndex/colId}) => void`)

> Deselects the specified cell.

For the shape of the argument see related [isCellSelected](#isCellSelected).

Also see related [selectCell](#selectCell).

### selectAll (`() => void`)

> Selects all cells in the DataGrid.

See related [deselectAll](#deselectAll).

### deselectAll (`() => void`)

> Deselects all cells in the DataGrid.

See related [selectAll](#selectAll).

### clear (`() => void`)

> An alias for [deselectAll](#deselectAll).

### selectRange (`(start, end) => void`)

> Selects the specified cell range.

The `start` and `end` arguments are objects of the same shape as the argument for [isCellSelected](#isCellSelected).

In order to select a range via mouse interaction, use `Cmd/Ctrl+Click` and `Shift+Click` as you would in a spreadsheet application.

Clicking a cell without holding the modifier keys will clear the selection and select the clicked cell.

**Example: Selecting a range via the Cell Selection API**

```ts
import {
  InfiniteTable,
  DataSource,
  InfiniteTableApi,
} from '@infinite-table/infinite-react';
import type { 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(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  id: { field: 'id' },
  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 [api, setApi] = React.useState<InfiniteTableApi<Developer> | null>(
    null,
  );
  return (
    <>
      <div
        style={{
          color: 'var(--infinite-cell-color)',
          background: 'var(--infinite-background)',
        }}
      >
        <button
          style={{
            margin: 10,
            padding: 10,
            borderRadius: 5,
            border: '2px solid magenta',
          }}
          onClick={() => {
            api?.cellSelectionApi.clear();
          }}
        >
          Clear
        </button>
        <button
          style={{
            margin: 10,
            padding: 10,
            borderRadius: 5,
            border: '2px solid magenta',
          }}
          onClick={() => {
            api?.cellSelectionApi.selectRange(
              {
                rowId: 1,
                colId: 'id',
              },
              {
                rowIndex: 10,
                colIndex: 3,
              },
            );
          }}
        >
          Select range
        </button>
      </div>

      <DataSource<Developer>
        primaryKey="id"
        data={dataSource}
        selectionMode="multi-cell"
      >
        <InfiniteTable<Developer>
          debugId="select-range-example"
          onReady={({ api }) => {
            setApi(api);
          }}
          columns={columns}
          columnDefaultWidth={100}
        />
      </DataSource>
    </>
  );
}
```

Don't worry if the `start` or `end` are not passed in the correct order - Infinite Table will figure it out.

For deselecting a range see [deselectRange](#deselectRange).

### deselectRange (`(start, end) => void`)

> Deselects the specified cell range.

The `start` and `end` arguments are objects of the same shape as the argument for [isCellSelected](#isCellSelected).

Don't worry if the `start` or `end` are not passed in the correct order - Infinite Table will figure it out.

For selecting a range see [selectRange](#selectRange).

**Example: Deselecting a range via the Cell Selection API**

```ts
import {
  InfiniteTable,
  DataSource,
  InfiniteTableApi,
} from '@infinite-table/infinite-react';
import type { 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(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  id: { field: 'id' },
  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 [api, setApi] = React.useState<InfiniteTableApi<Developer> | null>(
    null,
  );
  return (
    <>
      <div
        style={{
          color: 'var(--infinite-cell-color)',
          background: 'var(--infinite-background)',
        }}
      >
        <button
          style={{
            margin: 10,
            padding: 10,
            borderRadius: 5,
            border: '2px solid magenta',
          }}
          onClick={() => {
            api?.cellSelectionApi.deselectRange(
              {
                rowId: 1,
                colIndex: 0,
              },
              {
                rowIndex: 3,
                colIndex: 3,
              },
            );
          }}
        >
          Deselect range (1, 0) - (3, 3)
        </button>

        <button
          style={{
            margin: 10,
            padding: 10,
            borderRadius: 5,
            border: '2px solid magenta',
          }}
          onClick={() => {
            api?.cellSelectionApi.selectAll();
          }}
        >
          Select all
        </button>
      </div>

      <DataSource<Developer>
        primaryKey="id"
        data={dataSource}
        selectionMode="multi-cell"
        defaultCellSelection={{
          defaultSelection: true,
          deselectedCells: [],
        }}
      >
        <InfiniteTable<Developer>
          debugId="deselect-range-example"
          onReady={({ api }) => {
            setApi(api);
          }}
          columns={columns}
          columnDefaultWidth={100}
        />
      </DataSource>
    </>
  );
}
```
