# Column Sizing

Canonical page: https://infinite-table.com/docs/learn/columns/fixed-and-flexible-size

Columns are a core concept for `Infinite Table` and sizing columns is an important topic to master. Here is a summary of how columns can be sized:

- fixed-sized columns can be specified via [`columns.defaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultWidth)
- flexible columns need [`columns.defaultFlex`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultFlex)
- [`columns.minWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.minWidth) specifies the minimum size for a column
- [`columns.maxWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.maxWidth) is for the maximum width a column can take
- default values are available for all of the above:
  - [`columnDefaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnDefaultWidth) gives all columns (that are otherwise unconfigured) a default size
  - [`columnMinWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMinWidth) specifies the minimum width for all columns (that don't have one)
  - [`columnMaxWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMaxWidth) specifies the maximum width for all columns (that don't have one)

For fine-grained controlled-behavior on column sizing, use the controlled [`columnSizing`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing) prop (for uncontrolled variant, see [`defaultColumnSizing`](https://infinite-table.com/docs/reference/infinite-table-props.md#defaultColumnSizing)). If you want to get updates to columns changing size as a result of user interaction, use [`onColumnSizingChange`](https://infinite-table.com/docs/reference/infinite-table-props.md#onColumnSizingChange).

Use [`columnDefaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnDefaultWidth) to configure the default column width. If a column is not sized otherwise, this will be applied. The default value for [`columnDefaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnDefaultWidth) is `200` (pixels).

For setting a minimum and maximum width for all columns, use [`columnMinWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMinWidth) (defaults to `30`) and [`columnMaxWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMaxWidth) (defaults to `2000`) respectively.

## Understanding default column sizing

The easiest way to get started and specify a sizing behavior for columns is to use [column.defaultWidth](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultWidth), [column.defaultFlex](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultFlex) and/or [`columnDefaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnDefaultWidth) (including related pros for specifying limits, like [column.minWidth](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.minWidth), [column.maxWidth](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.maxWidth) and [`columnMinWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMinWidth) / [`columnMaxWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMaxWidth)).

Those properties have `default` in their name because after the initial rendering of a column, you can't change its size by updating those values - more technically, [column.defaultWidth](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultWidth) and [column.defaultFlex](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultFlex) are uncontrolled props.

We suggest you use those to get started and if you don't have care about responding to the user changing the widths of those columns via drag&drop. As long as you're not using [`onColumnSizingChange`](https://infinite-table.com/docs/reference/infinite-table-props.md#onColumnSizingChange) to be notified of column size changes, you're probably good with those.

## Controlled column sizing

However, once you start using [`onColumnSizingChange`](https://infinite-table.com/docs/reference/infinite-table-props.md#onColumnSizingChange) and want to have full control of column sizing (maybe you want to restore it later to the state the user had it when the app was closed), you probably want to use controlled [`columnSizing`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing).

The [`columnSizing`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing) prop is an object of column ids to column sizing objects. Those sizing objects can have the following properties:

- [flex](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing.flex) - use this for <b>flexible columns</b>. Behaves like the flex CSS property.
- [width](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing.width) - use this for <b>fixed sized columns</b>
- [minWidth](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing.minWidth) - specifies the minimum width of the column. Useful for flexible columns or for restricting users resizing both fixed and flexible columns.
- [maxWidth](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing.maxWidth) - specifies the maximum width of the column. Useful for flexible columns or for restricting users resizing both fixed and flexible columns.

If a column is not specified in the [`columnSizing`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing) prop (or its uncontrolled variant), or sized otherwise (eg: via the column type), it will have a fixed size, defaulting to [`columnDefaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnDefaultWidth) (which also defaults to `200` if no value is passed in). You can also specify a [`columnMinWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMinWidth) and [`columnMaxWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnMaxWidth) - those will be applied for all columns (namely for those that dont explicitly specify other min/max widths).

```tsx
const columnSizing: InfiniteTablePropColumnSizing = {
  country: {
    flex: 1,
    // minWidth is optional
    minWidth: 200,
  },
  city: {
    width: 400,
    // and so is maxWidth
    maxWidth: 500,
  },
  salary: {
    flex: 3,
  },
};
// any column not specified in the columnSizing (or defaultColumnSizing) prop
// will have fixed width (defaulting to `columnDefaultWidth`, which in turn defaults to 200px)
```

You might find specifying the column size outside the column object to be a bit verbose to start with, but it will be easier to manage in many cases and is much more flexible. For example, when the user resizes a column via drag & drop and you want to persist the new column sizes, you don't have to update the whole `columns` object but instead update [`columnSizing`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnSizing) alone.
The same principle is true for [`columnPinning`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnPinning) and other column-level props.

The `columnSizing` prop also has an uncontrolled version, namely [`defaultColumnSizing`](https://infinite-table.com/docs/reference/infinite-table-props.md#defaultColumnSizing).

## Using flexible column sizing

The way flex sizing is implemented is similar to how CSS flexbox algorithm works. Explore this section to find out more details.

Imagine you have `1000px` of space available to the viewport of `InfiniteTable` and you have 3 columns:

- a fixed column `100px` wide - name it col `A`
- a fixed column `300px` wide - name it col `B`
- a flexible column with `flex: 1` - name it col `F1`
- a flexible column with `flex: 2` - name it col `F2`

The space remaining for the flexible columns is `1000px - 400px = 600px` and the sum of all flex values is `3`, that means each `flex` unit will be `600px / 3 = 200px`.

This means columns will have the following sizes:

- col `A` will be `100px`
- col `B` will be `300px`
- col `F1` will be `200px` ( so a flex unit)
- col `F2` will be `400px` ( so the equivalent of `2` flex units)

If the browser changes the layout of the component, so `InfiniteTable` has only `700px` available, then a flex unit would be `(700px - 400px) / 3 = 100px`.

This means columns will have the following sizes:

- col `A` will be `100px`
- col `B` will be `300px`
- col `F1` will be `100px` ( so a flex unit)
- col `F2` will be `200px` ( so the equivalent of `2` flex units)

The flexbox algorithm also uses [`viewportReservedWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#viewportReservedWidth) to determine the width of the viewport to use for sizing columns - you can use [viewportReservedWidth=100](https://infinite-table.com/docs/reference/infinite-table-props.md#viewportReservedWidth) to always have a `100px` reserved area that won't be used for flexing columns.

 **Example: Using viewportReservedWidth to reserve whitespace when you have flexible columns**

 

This example has a `viewportReservedWidth` of `50px`.

 

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

export const columns: Record<string, InfiniteTableColumn<Employee>> = {
  firstName: {
    field: 'firstName',
    header: 'First Name',
  },
  country: {
    field: 'country',
    header: 'Country',
  },
  city: {
    field: 'city',
    header: 'City',
  },
  salary: {
    field: 'salary',
    type: 'number',
    header: 'Salary',
  },
};

const defaultColumnSizing: InfiniteTablePropColumnSizing = {
  country: { flex: 1 },
  city: { flex: 1 },
  salary: { flex: 2 },
};

export default function App() {
  const [viewportReservedWidth, setViewportReservedWidth] = useState(0);
  return (
    <>
      <div style={{ color: 'var(--infinite-cell-color' }}>
        <p>Current viewport reserved width: {viewportReservedWidth}px.</p>

        <button
          style={{
            padding: 5,
            margin: 5,
            border: '2px solid currentColor',
          }}
          onClick={() => {
            setViewportReservedWidth(0);
          }}
        >
          Click to reset viewportReservedWidth to 0
        </button>
      </div>
      <DataSource<Employee> data={dataSource} primaryKey="id">
        <InfiniteTable<Employee>
          debugId="viewportReservedWidth-example"
          columns={columns}
          columnDefaultWidth={50}
          viewportReservedWidth={viewportReservedWidth}
          onViewportReservedWidthChange={setViewportReservedWidth}
          defaultColumnSizing={defaultColumnSizing}
        />
      </DataSource>
    </>
  );
}

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

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;
};
```

Take a look at the snippet below to see column sizing at work with flexible and fixed columns.

**Example: Using controlled columnSizing**

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

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

  city: {
    field: 'city',
    header: 'City',
  },

  salary: {
    field: 'salary',
    type: 'number',
    header: 'Salary',
  },
};

export default function App() {
  const [columnSizing, setColumnSizing] =
    React.useState<InfiniteTablePropColumnSizing>({
      country: { width: 100 },
      city: { flex: 1, minWidth: 100 },
      salary: { flex: 2, maxWidth: 500 },
    });

  const [viewportReservedWidth, setViewportReservedWidth] = useState(0);

  return (
    <>
      <p style={{ color: 'var(--infinite-cell-color)' }}>
        Current column sizing:{' '}
        <code>
          <pre>{JSON.stringify(columnSizing, null, 2)}</pre>
        </code>
        Viewport reserved width: {viewportReservedWidth} -{' '}
        <button onClick={() => setViewportReservedWidth(0)}>
          click to reset to 0
        </button>
      </p>
      <DataSource<Employee> data={dataSource} primaryKey="id">
        <InfiniteTable<Employee>
          debugId="columnSizing-example"
          columns={columns}
          columnDefaultWidth={50}
          columnSizing={columnSizing}
          onColumnSizingChange={setColumnSizing}
          viewportReservedWidth={viewportReservedWidth}
          onViewportReservedWidthChange={setViewportReservedWidth}
        />
      </DataSource>
    </>
  );
}

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

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;
};
```

You might find [`viewportReservedWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#viewportReservedWidth) useful for advanced configuration when you have flexible columns.

When he user is performing a column resize (via drag & drop), [`onViewportReservedWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#onViewportReservedWidth) is called when the resize is finished (not the case for resizing with the **SHIFT** key pressed, when adjacent columns share the space between them).

You can also size (generated) group columns by using their [column.id](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.id) property.

For [groupRenderStrategy="multi-column"](https://infinite-table.com/docs/reference/infinite-table-props.md#groupRenderStrategy), if no `id` is specified in the group column configuration, each column will have a generated id like this: `"group-by-${field}"`.

For [groupRenderStrategy="single-column"](https://infinite-table.com/docs/reference/infinite-table-props.md#groupRenderStrategy), if no `id` is specified in the [`groupColumn`](https://infinite-table.com/docs/reference/infinite-table-props.md#groupColumn) it will default to: `"group-by"`.

## Resizing columns via drag & drop

Columns are user-resizable via drag & drop. If you don't want a column to be resizable, specify [column.resizable=false](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.resizable)

By default, all columns are resizable since [`resizableColumns`](https://infinite-table.com/docs/reference/infinite-table-props.md#resizableColumns) defaults to `true`. The [`resizableColumns`](https://infinite-table.com/docs/reference/infinite-table-props.md#resizableColumns) prop controls the behavior for all columns that don't explicitly specify their [column.resizable](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.resizable) property.

When initially rendered, columns are displayed with their [`columns.defaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultWidth) (you can also use [`columnDefaultWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#columnDefaultWidth)) or [`columns.defaultFlex`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.defaultFlex). Flexible columns take up available space taking into account their flex value, as detailed above.

When the user is resizing columns (or column groups), the effect is seen in real-time, so it's very easy to adjust the columns to desired widths. After the user drops the resize handle to the desired position, [`onColumnSizingChange`](https://infinite-table.com/docs/reference/infinite-table-props.md#onColumnSizingChange) is being called, to allow the developer to react to column sizing changes. Also [`onViewportReservedWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#onViewportReservedWidth) is called as well when the resize is finished (not the case for resizing with the **SHIFT** key pressed, when adjacent columns share the space between them).

When flexible columns are resized, they are kept flexible even after the resize. Note however that their flex values will be different to the original flex values and will reflect the new proportions each flex column is taking up at the moment of the resize.

More exactly, the new flex values will be the actual pixel widths. As an example, say there are 2 flex columns, first one with flex `1` and second one with flex `3` and they have an available space of `800px`.

```ts
const columns = {
  first: { flex: 1, field: 'one' },
  second: { flex: 2, field: 'two' },
};
```

Initially they will occupy `200px` and `600px` respectively. If the user resizes them to be of equal size, [`onColumnSizingChange`](https://infinite-table.com/docs/reference/infinite-table-props.md#onColumnSizingChange) will be called with an object like

```ts
{
  first: { flex: 400 },
  second: {flex: 400 }
}
```

since those are the actual widths measured from the DOM. This works out well, even if the available space of the table grows, as the proportions will be the same.

### Resize Restrictions

When resizing, the user needs to drag the resize handle to adjust the columns to new sizes. While doing so, the resize handle has a (green) color to indicate everything is okay. However, when restrictions are hit (either column [min](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.minWidth) or [max](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.maxWidth) widths), the resize handle turns red to indicate further resizing is not possible.

### Sharing space on resize

By default when resizing a specific column, the following columns are pushed to the right (when making the column wider) or moved to the left (when making the column narrower).

For sharing space between resizable columns when resizing, the user needs to **hold the SHIFT key** when grabbing the resize handle. When the handle is dropped and the resize confirmed, [`onColumnSizingChange`](https://infinite-table.com/docs/reference/infinite-table-props.md#onColumnSizingChange) is called, but [`onViewportReservedWidth`](https://infinite-table.com/docs/reference/infinite-table-props.md#onViewportReservedWidth) is not called for this scenario, since the reserved width is preserved.

### Resizing column groups

Just as columns are being resized, it is also possible to resize column groups. For this, the user needs to hover over the right border of the column group and start dragging the resize handle.

For multi-level column groups, it's possible to resize any of them. Just grab the handle from the desired group and start dragging. The handle height will indicate which column group is being resized.

If a column group has at least one resizable column, it can be resized.

When resizing, the space is shared proportionally betweem all resizable columns in the group.

Once a min/max limit has been reached for a certain column in the group, the column respects the limit and the other columns keep resizing as usual. When the min/max limit has been reached for all columns in the group, the resize handle turns red to indicate further resizing is no longer possible.

**Example: Resizing column groups**

Try resizing the `Finance` and `Regional Info` column groups.

The columns in the `Finance` group can be resized an extra `30px` (they have a `maxWidth` of `130px`).

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

const columns: InfiniteTablePropColumns<Developer> = {
  currency: {
    field: 'currency',
    columnGroup: 'finance',
    maxWidth: 130,
  },
  salary: {
    field: 'salary',
    columnGroup: 'finance',
    maxWidth: 130,
  },
  country: {
    field: 'country',
    columnGroup: 'regionalInfo',
    maxWidth: 400,
  },
  preferredLanguage: {
    field: 'preferredLanguage',
    columnGroup: 'regionalInfo',
  },
  id: { field: 'id', defaultWidth: 80 },
  firstName: {
    field: 'firstName',
  },
  stack: {
    field: 'stack',
  },
};

const columnGrous: Record<string, InfiniteTableColumnGroup> = {
  regionalInfo: {
    header: 'Regional Info',
  },
  finance: {
    header: 'Finance',
    columnGroup: 'regionalInfo',
  },
};

export default function ColumnValueGetterExample() {
  return (
    <>
      <DataSource<Developer> primaryKey="id" data={dataSource}>
        <InfiniteTable<Developer>
          debugId="column-groups-example"
          columnGroups={columnGrous}
          columns={columns}
          columnDefaultWidth={100}
        />
      </DataSource>
    </>
  );
}
```

### Customizing the resize handle colors

It's possible to customize the resize handle colors and width.

For adjusting the handle colors, use the following CSS variables:

- `--infinite-resize-handle-hover-background` - the color of the resize handle when it's in a `green`/all good state.
- `--infinite-resize-handle-constrained-hover-background` - the color of the resize handle when it has reached a min/max constraint.

You can also adjust the width of the resize handle:

- `--infinite-resize-handle-width` - the width of the `green`/`red` column resize handle. Defaults to `2px`
- `--infinite-resize-handle-active-area-width` - the width of the area you can hover over in order to grab the resize handle. Defaults to `20px`. The purpose of this active area is to make it easier to grab the resize handle.

## Auto-sizing columns

For sizing columns to the width of their content, you can use [`autoSizeColumnsKey`](https://infinite-table.com/docs/reference/infinite-table-props.md#autoSizeColumnsKey) to declaratively auto-size columns:

- when [`autoSizeColumnsKey`](https://infinite-table.com/docs/reference/infinite-table-props.md#autoSizeColumnsKey) is a `string` or `number` and the value of the prop is changed, all columns will be auto-sized.
- when [`autoSizeColumnsKey`](https://infinite-table.com/docs/reference/infinite-table-props.md#autoSizeColumnsKey) is an object, it needs to have a `key` property (of type `string` or `number`), so whenever the `key` changes, the columns will be auto-sized. Specifying an object for [`autoSizeColumnsKey`](https://infinite-table.com/docs/reference/infinite-table-props.md#autoSizeColumnsKey) gives you more control over which columns are auto-sized and if the size measurements include the header or not.

When an object is used, the following properties are available:

- `key` - mandatory property, which, when changed, triggers the update
- `includeHeader` - optional boolean, - decides whether the header will be included in the auto-sizing calculations. If not specified, `true` is assumed.
- `columnsToSkip` - a list of column ids to skip from auto-sizing. If this is used, all columns except those in the list will be auto-sized.
- `columnsToResize` - the list of column ids to include in auto-sizing. If this is used, only columns in the list will be auto-sized.

**Example: Auto-sizing columns**

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

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

export default function GroupByExample() {
  const [key, setKey] = React.useState(0);
  const [includeHeader, setIncludeHeader] = React.useState(false);

  const autoSizeColumnsKey = React.useMemo(() => {
    return {
      includeHeader,
      key,
    };
  }, [key, includeHeader]);
  return (
    <>
      <div
        style={{
          color: 'var(--infinite-cell-color)',
          background: 'var(--infinite-background)',
        }}
      >
        <label>
          <input
            checked={includeHeader}
            type={'checkbox'}
            onChange={(e) => {
              setIncludeHeader(e.target.checked);
            }}
          />{' '}
          Include header
        </label>

        <button
          style={{
            margin: 10,
            padding: 10,
            borderRadius: 5,
            border: '2px solid magenta',
          }}
          onClick={() => {
            setKey((key) => key + 1);
          }}
        >
          Click to auto-size
        </button>
      </div>

      <DataSource<Developer> primaryKey="id" data={dataSource}>
        <InfiniteTable<Developer>
          debugId="autoSizeColumnsKey-example"
          autoSizeColumnsKey={autoSizeColumnsKey}
          columns={columns}
          columnDefaultWidth={200}
        />
      </DataSource>
    </>
  );
}
```
