# Keyboard Shorcuts

> Infinite React DataGrid supports user-friendly keyboard shortcuts for executing custom actions.

Canonical page: https://infinite-table.com/docs/learn/keyboard-navigation/keyboard-shortcuts

The React DataGrid supports defining [keyboard shorcuts](https://infinite-table.com/docs/reference/infinite-table-props.md#keyboardShortcuts) for performing custom actions.

A keyboard shortcut is defined as an object of the following shape:
  
```ts
{
  key: string;
  when?: (context) => boolean | Promise<boolean>;
  handler: (context, event) => void | Promise<void>;
}
```

The `key` definition is what you're used to from VS Code and other applications - it can be
 * a single character: `t`, `x`, etc...
 * a combination of characters (e.g. `Ctrl+Shift+p`,`Cmd+Shift+Enter`) - key modifiers are supported, and can be added with the `+` (plus) sign.
 * or a special key (e.g. `Enter`, `ArrowUp`, `ArrowDown`, ` ` (space), `Escape`, `Delete`, `Insert`, `PageDown`,`PageUp`,`F1`, `F2`, etc).

 Examples of valid shortcuts: `Cmd+Shift+e`, `Alt+Shift+Enter`, `Shift+PageDown`, `Ctrl+x`

There's a special key `*` that matches any key. This can be useful when you want to define a keyboard shortcut that should be triggered on any key press.

Another important key is the `Cmd|Ctrl` key, which matches both the `Cmd` key on Mac and the `Ctrl` key on Windows/Linux.

Example combinations: `Cmd|Ctrl+Shift+Enter`, `Cmd|Ctrl+e`, `Cmd|Ctrl+Shift+i`.

**Example**

Click on a cell and use the keyboard to navigate.

Press `Shift+Enter` to show an alert with the current active cell position.

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

const columns: InfiniteTablePropColumns<Developer> = {
  preferredLanguage: { field: 'preferredLanguage', header: 'Language' },
  country: { field: 'country', header: 'Country' },
  salary: {
    field: 'salary',
    type: 'number',
  },
  age: { field: 'age' },
  canDesign: { field: 'canDesign' },
  firstName: { field: 'firstName' },
  stack: { field: 'stack' },
  id: { field: 'id' },
  hobby: { field: 'hobby' },
  city: { field: 'city' },
  currency: { field: 'currency' },
};

export default function KeyboardShortcuts() {
  return (
    <>
      <DataSource<Developer> primaryKey="id" data={dataSource}>
        <InfiniteTable<Developer>
          debugId="keyboard-shortcuts-initial-example"
          columns={columns}
          keyboardShortcuts={[
            {
              key: 'Shift+Enter',
              when: (context) => !!context.getState().activeCellIndex,
              handler: (context) => {
                const { activeCellIndex } = context.getState();

                const [rowIndex, columnIndex] = activeCellIndex!;
                alert(
                  `Current active cell: row ${rowIndex}, column ${columnIndex}.`,
                );
              },
            },
            {
              key: 'PageUp',
              handler: () => {
                console.log('PageUp key pressed.');
              },
            },
            {
              key: 'PageDown',
              handler: () => {
                console.log('PageDown key pressed.');
              },
            },
          ]}
        />
      </DataSource>
    </>
  );
}
```

Keyboard shortcuts have a `when` optional property. If defined, it restricts when the `handler` function is called. The handler will only be called when the handler returns `true`.

## Implementing Keyboard Shortcut Handlers

Both the `handler` function and the `when` function of a keyboard shorcut are called with an object that gives access to the following:
 - `api` - a reference to the [Infinite Table API](https://infinite-table.com/docs/reference/api/index.md) object.
 - `dataSourceApi` - a reference to the [DataSource API](https://infinite-table.com/docs/reference/datasource-api/index.md) object.
 - `getState` - a function that returns the current state of the grid.
 - `getDataSourceState` - a function that returns the current state of the data source.

The second parameter of the `handler` function is the `event` object that triggered the keyboard shortcut.

## Predefined Keyboard Shortcuts

Infinite Table DataGrid comes with some predefined keyboard shorcuts.
you can import from the `keyboardShortcuts` named export.
```ts
import { keyboardShortcuts } from '@infinite-table/infinite-react'
```

### Instant Edit

```ts {4,12}
import {
  DataSource,
  InfiniteTable,
  keyboardShortcuts
} from '@infinite-table/infinite-react';

 function App() {
  return <DataSource<Developer> primaryKey="id" data={dataSource}>
    <InfiniteTable<Developer>
      columns={columns}
      keyboardShortcuts={[
        keyboardShortcuts.instantEdit
      ]}
    />
  </DataSource>
}
```

For now, the only predefined keyboard shorcut is `keyboardShortcuts.instantEdit`. This keyboard shorcut starts cell editing when any key is pressed on the active cell. This is the same behavior found in Excel/Google Sheets.

**Example**

Click on a cell and then start typing to edit the cell.

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

const columns: InfiniteTablePropColumns<Developer> = {
  preferredLanguage: { field: 'preferredLanguage', header: 'Language' },
  country: { field: 'country', header: 'Country' },
  salary: {
    field: 'salary',
    type: 'number',
  },
  age: { field: 'age' },
  canDesign: { field: 'canDesign' },
  firstName: { field: 'firstName' },
  stack: { field: 'stack' },
  id: { field: 'id', defaultEditable: false },
  hobby: { field: 'hobby' },
  city: { field: 'city' },
  currency: { field: 'currency' },
};

export default function KeyboardShortcuts() {
  return (
    <>
      <DataSource<Developer> primaryKey="id" data={dataSource}>
        <InfiniteTable<Developer>
          debugId="keyboard-shortcuts-instant-edit-example"
          columns={columns}
          columnDefaultEditable
          keyboardShortcuts={[keyboardShortcuts.instantEdit]}
        />
      </DataSource>
    </>
  );
}
```
