Working with 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 prop is typed either as
  • Record<string, InfiniteTableColumn<DATA_TYPE>>
  • or InfiniteTablePropColumns<DATA_TYPE>, which is an alias for the type above

Understanding column id

In InfiniteTable, columns are identified by their key in the columns object. We'll refer to this as the column id. The column ids are used in many places - like defining the column order, column pinning, column visibility, etc.
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.
View Mode
Fork
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> columns={columns} columnDefaultWidth={200} />
    </DataSource>
  );
}

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

Learn more about customizing Column Rendering

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 reference.
There are two special column types 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.

Learn more on Column Types

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 object. You can however control that explicitly by using the columnOrder: string[] prop.

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 prop is an array of strings, representing the column ids. A column id is the key of the column in the columns object.
The columnOrder array can contain identifiers that are not yet defined in the columns Map, or can contain duplicate ids. This is a feature, not a bug. We want to allow you to use the columnOrder in a flexible way so it can define the order of current and future columns.
columnOrder is a controlled prop. For the uncontrolled version, see defaultColumnOrder
When using controlled columnOrder, make sure you also update the order by using the onColumnOrderChange callback prop.
View Mode
Fork
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>
          columns={columns}
          columnOrder={columnOrder}
          onColumnOrderChange={setColumnOrder}
          columnDefaultWidth={200}
        />
      </DataSource>
    </>
  );
}

const dataSource = () => {

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.