# Infinite Table Row Selection API

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

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

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

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

You can retrieve the row selection api by reading it from the `api.rowSelectionApi` property.

```tsx {4}

const onReady = ({api}: {api:InfiniteTableApi<DATA_TYPE>}) => {
  // do something with it
  api.rowSelectionApi.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 Cell Selection API page](https://infinite-table.com/docs/reference/cell-selection-api/index.md) for the cell selection API.
See the [Infinite Table Column API page](https://infinite-table.com/docs/reference/column-api/index.md) for the column API.
See the [Infinite Table Row Detail API page](https://infinite-table.com/docs/reference/row-detail-api/index.md) for the row detail API (when master-detail is configured).

### allRowsSelected (`boolean`)

> Boolean getter to report whether all the rows are selected or not

### deselectGroupRow (`(groupKeys: any[]) => void`)

> Deselects the group row that is identified by the given group keys. Only makes sense when the DataSource is [grouped](https://infinite-table.com/docs/reference/datasource-props/index.md#groupBy).

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For selecting a group row, see related [selectGroupRow](#selectGroupRow).

Most often, you don't need to use this imperative way of selecting group rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) to exclude the group row from the selection.

### deselectRow (`(primaryKey: any, groupKeys?: any[]) => boolean`)

> Deselects the specified row. Optionally provide the group keys, if you have access to them.

See note from [isRowSelected](#isRowSelected) for whether you need to provide the `groupKeys` or not.

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For selecting the row, see related [selectRow](#selectRow).

Most often, you don't need to use this imperative way of deselecting rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) to remove the row you want from the selection.

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

> Deselects all the rows in the DataSource.

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For selecting all rows, see related [selectAll](#selectAll).

Most often, you don't need to use this imperative way of deselecting all rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) (when multiple row selection is enabled) to a value of

```tsx
{ defaultSelection: false, selectedRows: []}
```

### getGroupRowSelectionState (`(groupKeys: any[], rowSelection?: DataSourceRowSelection) => true|false|null`)

> Returns the state of a group row - only applicable when the DataSource is [grouped](https://infinite-table.com/docs/reference/datasource-props/index.md#groupBy)

The returned values can be:

- `true` - the group row and all its children are selected, at any level of nesting
- `false` - the group row and all its children are deselected, at any level of nesting
- `null` - the group row has some (not all) children selected, at any level of nesting

Baiscally, `true` means the group row and all children are selected, `false` means the group row is not selected and doesn't have any selected children, while `null` is the indeterminate state, where just some (but not all) of the children of the group are selected.

If you provide a the value of a `rowSelection`, it will be used as the source of truth for selection. If no value for `rowSelection` is provided, it will use the current row selection.

If you don't provide a value for the `rowSelection` and are calling this method in the [`onRowSelectionChange`](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange) callback prop, you might be one step behind the selection. In such a case, make sure you pass to this function the value you receive in the [`onRowSelectionChange`](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange) callback.

### getSelectedPrimaryKeys (`(rowSelection?: DataSourceRowSelection) => (string|number)[]`)

> Retrieves the ids (primary keys) of the selected rows, when the selection contains group keys instead of primary keys (so when [`useGroupKeysForMultiRowSelection`](https://infinite-table.com/docs/reference/datasource-props/index.md#useGroupKeysForMultiRowSelection) is `true` and the DataSource is [grouped](https://infinite-table.com/docs/reference/datasource-props/index.md#groupBy)).

If you provide a the value of a `rowSelection`, it will be used as the source of truth for retrieving the row ids. If no value for `rowSelection` is provided, it will use the current row selection.

This will not work properly when the `DataSource` is configured with [lazy loading](https://infinite-table.com/docs/reference/datasource-props/index.md#lazyLoad), since it cannot give you primary keys of rows not yet loaded.

If you don't provide a value for the `rowSelection` and are calling this method in the [`onRowSelectionChange`](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange) callback prop, you might be one step behind the selection. In such a case, make sure you pass to this function the value you receive in the [`onRowSelectionChange`](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange) callback.

**Example: Using getSelectedPrimaryKeys in multi row checkbox selection with grouping**

This example shows how you can use getSelectedPrimaryKeys with multiple row selection to retrieve the actual ids of the selected rows.

```ts
import { InfiniteTable, DataSource } from '@infinite-table/infinite-react';
import type {
  InfiniteTableProps,
  InfiniteTableApi,
  InfiniteTablePropColumns,
  DataSourceProps,
  DataSourcePropRowSelection_MultiRow,
} from '@infinite-table/infinite-react';
import * as React from 'react';
import { useCallback, useRef, useEffect, useState } from 'react';

const columns: InfiniteTablePropColumns<Developer> = {
  country: {
    field: 'country',
  },
  firstName: {
    field: 'firstName',
    defaultHiddenWhenGroupedBy: '*',
  },
  stack: {
    field: 'stack',
    renderGroupValue: ({ value }) => `Stack: ${value || ''}`,
  },
  age: { field: 'age' },
  id: { field: 'id' },
  preferredLanguage: {
    field: 'preferredLanguage',
    renderGroupValue: ({ value }) => `Lang: ${value || ''}`,
  },
  canDesign: {
    field: 'canDesign',
    renderGroupValue: ({ value }) => `Can design: ${value || ''}`,
  },
};

const defaultGroupBy: DataSourceProps<Developer>['groupBy'] = [
  {
    field: 'canDesign',
  },
  {
    field: 'stack',
  },
  {
    field: 'preferredLanguage',
  },
];

const groupColumn: InfiniteTableProps<Developer>['groupColumn'] = {
  field: 'firstName',
  renderSelectionCheckBox: true,
  defaultWidth: 300,
};

const domProps = {
  style: {
    flex: 1,
    minHeight: 500,
  },
};

export default function App() {
  const apiRef = useRef<InfiniteTableApi<Developer> | null>(null);
  const [rowSelection, setRowSelection] =
    useState<DataSourcePropRowSelection_MultiRow>({
      selectedRows: [
        ['yes', 'backend', 'TypeScript'],
        ['yes', 'backend', 'Go'],
        16,
        26,
        30,
        ['yes', 'frontend'],
      ],
      deselectedRows: [4, 2],
      defaultSelection: false,
    });

  const [selectedIds, setSelectedIds] = useState<string[]>([]);

  const onReady = useCallback(
    ({ api }: { api: InfiniteTableApi<Developer> }) => {
      apiRef.current = api;

      setSelectedIds(
        api.rowSelectionApi.getSelectedPrimaryKeys(rowSelection) as string[],
      );
    },
    [],
  );

  useEffect(() => {
    if (!apiRef.current) {
      return;
    }
    setSelectedIds(
      apiRef.current.rowSelectionApi.getSelectedPrimaryKeys(
        rowSelection,
      ) as string[],
    );
  }, [rowSelection]);
  return (
    <div
      style={{
        display: 'flex',
        flex: 1,
        overflow: 'auto',
        color: 'var(--infinite-cell-color)',
        flexFlow: 'column',
        background: 'var(--infinite-background)',
      }}
    >
      <div
        style={{
          padding: 10,
        }}
      >
        Current row selection:
        <code
          style={{
            display: 'block',
            height: 300,
            overflow: 'auto',
            border: '1px dashed currentColor',
          }}
        >
          <pre> {JSON.stringify(rowSelection, null, 2)}.</pre>
        </code>
        Current selected ids: {selectedIds.join(', ')}
      </div>

      <DataSource<Developer>
        data={dataSource}
        groupBy={defaultGroupBy}
        rowSelection={rowSelection}
        onRowSelectionChange={setRowSelection}
        useGroupKeysForMultiRowSelection
        primaryKey="id"
      >
        <InfiniteTable<Developer>
          debugId="controlled-multi-row-selection-example-with-group-keys"
          onReady={onReady}
          columns={columns}
          domProps={domProps}
          groupColumn={groupColumn}
          columnDefaultWidth={150}
        />
      </DataSource>
    </div>
  );
}

const dataSource = () => {
  return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers100')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

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

### isRowSelected (`(primaryKey: any, groupKeys?: any[]) => boolean`)

> Checks if a row specified by its primary key is selected or not. Optionally provide the group keys, if you have access to them.

The group keys are not mandatory, and they are useful only when the DataSource is [grouped](https://infinite-table.com/docs/reference/datasource-props/index.md#groupBy).

Even if you don't pass them, the component will try to retrieve them from its internal state - note though that in lazy-load scenarios, not all rows/groups may have been loaded, so in this case, you have to make sure you provide the `groupKeys` when calling this method.

### isRowDeselected (`(primaryKey: any, groupKeys?: any[]) => boolean`)

> Checks if a row specified by its primary key is deselected or not. Optionally provide the group keys, if you have access to them.

See note from [isRowSelected](#isRowSelected)

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

> Selects all the rows in the DataSource.

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For deselecting all rows, see related [deselectAll](#deselectAll).

Most often, you don't need to use this imperative way of selecting rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) (when multiple row selection is enabled) to a value of

```tsx
{ defaultSelection: true, deselectedRows: []}
```

### selectGroupRow (`(groupKeys: any[]) => void`)

> Selects the group row that is identified by the given group keys. Only makes sense when the DataSource is [grouped](https://infinite-table.com/docs/reference/datasource-props/index.md#groupBy).

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For deselecting a group row, see related [deselectGroupRow](#deselectGroupRow).

Most often, you don't need to use this imperative way of selecting group rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) to include the group row you want to select.

### selectRow (`(primaryKey: any, groupKeys?: any[]) => boolean`)

> Selects the specified row. Optionally provide the group keys, if you have access to them.

See note from [isRowSelected](#isRowSelected) for whether you need to provide the `groupKeys` or not.

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For deselecting the row, see related [deselectRow](#deselectRow).

Most often, you don't need to use this imperative way of selecting rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) to include the row you want in the selection.

### toggleGroupRowSelection (`(groupKeys: any[]) => void`)

> Toggles the selection of the group row that is identified by the given group keys. Only makes sense when the DataSource is [grouped](https://infinite-table.com/docs/reference/datasource-props/index.md#groupBy).

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For deselecting a group row, see related [deselectGroupRow](#deselectGroupRow).
For selecting a group row, see related [selectGroupRow](#selectGroupRow).

Most often, you don't need to use this imperative way of selecting group rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) to include the group row you want to select.

### toggleRowSelection (`(primaryKey: any, groupKeys?: any[]) => boolean`)

> Toggles the selection of the specified row. Optionally provide the group keys, if you have access to them.

See note from [isRowSelected](#isRowSelected) for whether you need to provide the `groupKeys` or not.

Calling this method triggers a call to [DataSource.onRowSelectionChange](https://infinite-table.com/docs/reference/datasource-props/index.md#onRowSelectionChange).

For deselecting the row, see related [deselectRow](#deselectRow).
For selecting the row, see related [selectRow](#selectRow).
For toggling the selection for a group row, see related [toggleGroupRowSelection](#toggleGroupRowSelection).

Most often, you don't need to use this imperative way of selecting rows. Simply update the [DataSource.rowSelection](https://infinite-table.com/docs/reference/datasource-props/index.md#rowSelection) to include or exclude the given row.
