# Working with Columns

> Define columns to configure your Infinite Table React DataGrid - fixed and flexible columns, resize, column groups and more

Canonical page: https://infinite-table.com/docs/learn/columns/

Columns are a central feature in `InfiniteTable`.

You define columns as a an object, with keys being column ids while values are the column definitions.

You then use them in the `columns` prop in your `InfiniteTable` component.

The [`columns`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns) prop is typed either as

- `Record<string, InfiniteTableColumn<DATA_TYPE>>`
- or `InfiniteTablePropColumns<DATA_TYPE>`, which is an alias for the type above

In `InfiniteTable`, columns are identified by their key in the [`columns`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns) object. **We'll refer to this as the column id**.
The column ids are used in many places - like defining the [column order](https://infinite-table.com/docs/reference/infinite-table-props.md#columnOrder), column pinning, column visibility, etc.

```ts
export type Employee = {
  id: number;
  companyName: string;
  firstName: string;
  lastName: string;
  country: string;
  city: string;
  department: string;
  team: string;
  salary: number;

};

// InfiniteTableColumn is a generic type, you have to bind it to a specific data-type
import { InfiniteTableColumn } from '@infinite-table/infinite-react';

// we're binding it here to the `Employee` type
// which means the `column.field` has to be `keyof Employee`
export const columns: Record<string, InfiniteTableColumn<Employee>> = {
  'firstName':
  {
    field: 'firstName',
    header: 'First Name',
  },
  'country':
  {
    field: 'country',
  },
  'city':
  {
    field: 'city'
  },
  'salary':
  {
    field: 'salary',
    type: 'number'
  },
}
<InfiniteTable columns={columns} />
```

It's very important to remember you should not pass a different reference of a prop on each render. `<InfiniteTable />` is a optimized to only re-render when props change - so if you change the props on every re-render you will get a performance penalty.

You should use `React.useCallback` / `React.useMemo` / `React.useState` to make sure you only update the props you pass down to `InfiniteTable` when you have to.

**Example: Basic Column Configuration**

```ts
import {
  InfiniteTable,
  DataSource,
  type InfiniteTableColumn,
} from '@infinite-table/infinite-react';

import * as React from 'react';

export type Employee = {
  id: number;
  companyName: string;
  companySize: string;
  firstName: string;
  lastName: string;
  country: string;
  countryCode: string;
  city: string;
  streetName: string;
  streetNo: string;
  department: string;
  team: string;
  salary: number;
  age: number;
  email: string;
};

export const columns: Record<string, InfiniteTableColumn<Employee>> = {
  firstName: {
    field: 'firstName',
    header: 'First Name',
  },
  country: {
    field: 'country',
    header: 'Country',
    columnGroup: 'location',
  },
  city: {
    field: 'city',
    header: 'City',
    columnGroup: 'address',
  },
  salary: {
    field: 'salary',
    type: 'number',
    header: 'Salary',
  },
  department: {
    field: 'department',
    header: 'Department',
  },
  team: {
    field: 'team',
    header: 'Team',
  },
  company: { field: 'companyName', header: 'Company' },

  companySize: {
    field: 'companySize',
    header: 'Company Size',
  },
};

export default function App() {
  return (
    <DataSource<Employee> data={dataSource} primaryKey="id">
      <InfiniteTable<Employee>
        debugId="basic-columns-example"
        columns={columns}
        columnDefaultWidth={200}
      />
    </DataSource>
  );
}

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

Find out how to render custom content inside columns or even take full control of column cells and header.

## Column Types

Column types allow you to customize column behavior and appearance for multiple columns at once. Most of the properties available for columns are also available for column types - for a full list, see [columnTypes](https://infinite-table.com/docs/reference/infinite-table-props.md#columnTypes) reference.

There are two special [column types](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.type) for now, but more are coming soon:

- `default` - all columns have this type, if not otherwise specified. The type does not contain any configuration, but allows you to define it and apply common configuration to all columns.
- `number` - if specified on a column (in combination with local uncontrolled sorting), the column will be sorted numerically.

Find out how to use column types to customize the appearance and behaviour of your columns.

## Column Order

The implicit column order is the order in which columns have been defined in the [`columns`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns) object. You can however control that explicitly by using the `columnOrder: string[]` prop.

```tsx

const columnOrder = ['firstName','id','curency']

const App = () => {
  return <DataSource<DATA_TYPE> primaryKey={"id"} dataSource={...}>
    <InfiniteTable<DATA_TYPE>
      columnOrder={columnOrder}
      onColumnOrderChange={(columnOrder: string[]) => {}}
    />
  </DataSource>
}
```

The [`columnOrder`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnOrder) prop is an array of strings, representing the column ids. A column id is the key of the column in the [`columns`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns) object.

The [`columnOrder`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnOrder) array can contain identifiers that are not yet defined in the [`columns`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns) Map, or can contain duplicate ids. This is a feature, not a bug. We want to allow you to use the [`columnOrder`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnOrder) in a flexible way so it can define the order of current and future columns.

[`columnOrder`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnOrder) is a controlled prop. For the uncontrolled version, see [`defaultColumnOrder`](https://infinite-table.com/docs/reference/infinite-table-props.md#defaultColumnOrder)

When using controlled [`columnOrder`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnOrder), make sure you also update the order by using the [`onColumnOrderChange`](https://infinite-table.com/docs/reference/infinite-table-props.md#onColumnOrderChange) callback prop.

**Example: Column Order demo, with firstName col displayed twice**

```tsx
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
} from '@infinite-table/infinite-react';
import * as React from 'react';
import { useState } from 'react';

export type Employee = {
  id: number;
  companyName: string;
  companySize: string;
  firstName: string;
  lastName: string;
  country: string;
  countryCode: string;
  city: string;
  streetName: string;
  streetNo: string;
  department: string;
  team: string;
  salary: number;
  age: number;
  email: string;
};

export const columns: InfiniteTablePropColumns<Employee> = {
  firstName: {
    field: 'firstName',
    header: 'First Name',
  },
  country: {
    field: 'country',
    header: 'Country',
    columnGroup: 'location',
  },

  city: {
    field: 'city',
    header: 'City',
    columnGroup: 'address',
  },
  salary: {
    field: 'salary',
    type: 'number',
    header: 'Salary',
  },
  department: {
    field: 'department',
    header: 'Department',
  },
  team: {
    field: 'team',
    header: 'Team',
  },
  company: { field: 'companyName', header: 'Company' },

  companySize: {
    field: 'companySize',
    header: 'Company Size',
  },
};

export default function App() {
  const [columnOrder, setColumnOrder] = useState<string[]>([
    'firstName',
    'country',
    'team',
    'company',
    'department',
    'companySize',
  ]);

  return (
    <>
      <div style={{ color: 'var(--infinite-cell-color)' }}>
        <p>
          Current column order:{' '}
          <code>
            <pre>{columnOrder.join(', ')}.</pre>
          </code>
        </p>
        <p>Drag column headers to reorder.</p>
      </div>

      <DataSource<Employee> data={dataSource} primaryKey="id">
        <InfiniteTable<Employee>
          debugId="columnOrder-example"
          columns={columns}
          columnOrder={columnOrder}
          onColumnOrderChange={setColumnOrder}
          columnDefaultWidth={200}
        />
      </DataSource>
    </>
  );
}

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

By keeping the column order simple, namely an array of strings, ordering becomes much easier.

The alternative would be to make `columns` an array, which most DataGrids do - and whenever they are reordered, a new `columns` array would be needed.
