React Infinite Table allows columns to be reordered in the grid by drag-and-drop. Drag columns around (start dragging the colum header) to change their order and arrange them in the desired position.

Note

Column ordering via drag & drop works by default.

You don’t have to specify an initial column order or any other callback props to update the column order. The default behavior of the component is to initially display all columns that are provided in the columns object (in the iteration order of the object keys).

If using the default uncontrolled column order is not enough, try using the controlled columnOrder prop, which gives you full control over the order of the columns - in this case, you have to update the column order as a result of user interaction, by specyfing onColumnOrderChange.

Column reordering via drag & drop with controlled `columnOrder`
View Mode
Fork
import * as React from 'react';
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
} from '@infinite-table/infinite-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 = () => {
  return fetch(
    'https://infinite-table.com/.netlify/functions/json-server' + '/employees100'
  )
    .then((r) => r.json())
    .then((data: Employee[]) => data);
};

Note

Column order can also be used in order to limit/modify the visible columns. Specify a limited number of columns in the columnOrder array and only those columns will be displayed.

For more advanced control on visibility, see columnVisibility.

The columnOrder array can contain any number of columns, even duplicate columns or random strings - the behavior is that any column ids which are not found in the columns object are ignored, while columns mentioned multiple times will be included multiple times, as indicated in the column order. Displaying the same column twice is a perfectly valid use case.

Advanced column order example
In this example, columnOrder is used as a controlled property, also as a way of limiting the visible columns.
View Mode
Fork
import * as React from 'react';
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
} from '@infinite-table/infinite-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[] | true
  >([
    'firstName',
    'country',
    'team',
    'company',
    'firstName',
    'not existing column',
    'companySize',
  ]);

  return (
    <>
      <div style={{ color: 'var(--infinite-cell-color)' }}>
        <p>
          Current column order:{' '}
          <code>
            <pre>{JSON.stringify(columnOrder)}.</pre>
          </code>
        </p>
        <p>
          Note: if the column order contains columns that
          don't exist in the `columns` definition, they will
          be skipped.
        </p>

        <button
          style={{
            border: '2px solid currentColor',
            padding: 5,
          }}
          onClick={() => {
            setColumnOrder(['firstName', 'country']);
          }}>
          Click to only show "firstName" and "country".
        </button>

        <button
          style={{
            border: '2px solid currentColor',
            padding: 5,
            marginLeft: 5,
          }}
          onClick={() => {
            setColumnOrder(true);
          }}>
          Click to reset column order.
        </button>
      </div>

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

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

Note

The columnOrder prop can either be an array of strings (column ids) or the boolean true. When true, all columns present in the columns object will be displayed, in the iteration order of the object keys - in the example above, try clicking the "Click to reset column order" button.

For all of the above examples, columnVisibility will also be taken into account, as it is the last source of truth for the visibility of a column.

Using columnOrder in combination with columnVisibility is very powerful - for example, you can have a specific column order even for columns which are not visible at a certain moment, so when they will be made visible, you’ll know exactly where they will be displayed.