You can use any field available in the DataSource to do the grouping - it can even be a field that is not a column.

Note

When using TypeScript, both DataSource and InfiniteTable components are generic and need to be rendered/instantiated with a DATA_TYPE parameter. The fields in that DATA_TYPE can then be used for grouping.

type Person = {
  name: string;
  age: number;
  country: string;
  id: string;
}

const groupRowsBy = [{field: 'country'}]

<DataSource<Person> groupRowsBy={groupRowsBy}>
  <InfiniteTable<Person> />
</DataSource>

In the example above, we’re grouping by country, which is a field available in the Person type. Specifying a field not defined in the Person type would be a type error.

Additionally, a column object can be used together with the field to define how the group column should be rendered.

const groupRowsBy = [
  {
    field: 'country',
    column: {
      width: 150,
      header: 'Country group',
    }
  }
]

The example below puts it all together.

Also see the groupRowsBy API reference to find out more.

Simple row grouping
Fork
import * as React from 'react';
import {
  InfiniteTable,
  DataSource,
  DataSourcePropGroupRowsBy,
} from '@infinite-table/infinite-react';

import { columns, Employee } from './columns';

const groupRowsBy: DataSourcePropGroupRowsBy<Employee> = [
  {
    field: 'country',
    column: {
      width: 150,
      header: 'Country group',
      renderValue: ({ value }) => <>Country: {value}</>,
    },
  },
];

export default function App() {
  return (
    <DataSource<Employee>
      data={dataSource}
      primaryKey="id"
      groupRowsBy={groupRowsBy}>
      <InfiniteTable<Employee> columns={columns} />
    </DataSource>
  );
}

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

In groupRowsBy.column you can use any column property - so, for example, you can define a custom renderValue function to customize the rendering.

const groupRowsBy = [
  {
    field: 'country',
    column: {
      renderValue: ({ value }) => <>Country: {value}</>,
    }
  }
]

Grouping strategies

When you want to group by multiple fields, InfiniteTable offers multiple grouping strategies:

  • multi column mode - the default.
  • single column mode
  • inline mode

You can specify the rendering strategy by setting the groupRenderStrategy property to any of the following: multi-column, single-column or inline.

Multiple groups columns

When grouping by multiple fields, by default the component will render a group column for each group field

const groupRowsBy = [
  {
    field: 'age',
    column: {
      width: 100,      
      renderValue: ({ value }) => <>Age: {value}</>,
    }
  },
  {
    field: 'companyName'
  },
  {
    field: 'country'
  }
]

Let’s see an example of how the component would render the table with the multi-column strategy.

Multi-column group render strategy
Fork
import * as React from 'react';
import {
  InfiniteTable,
  DataSource,
  DataSourcePropGroupRowsBy,
} from '@infinite-table/infinite-react';
import { columns, Employee } from './columns';

const groupRowsBy: DataSourcePropGroupRowsBy<Employee> = [
  {
    field: 'age',
    column: {
      renderValue: ({ value }: { value: any }) =>
        `Age: ${value}`,
    },
  },
  {
    field: 'companyName',
  },
];

export default function App() {
  return (
    <DataSource<Employee>
      data={dataSource}
      primaryKey="id"
      groupRowsBy={groupRowsBy}>
      <InfiniteTable<Employee>
        columns={columns}
        columnDefaultWidth={150}
      />
    </DataSource>
  );
}

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

For the multi-column strategy, you can use hideEmptyGroupColumns in order to hide columns for groups which are currently not visible.

Hide Empty Group Columns
Fork
import * as React from 'react';
import {
  InfiniteTable,
  DataSource,
  DataSourcePropGroupRowsBy,
  InfiniteTableGroupColumnFunction,
  InfiniteTablePropGroupRenderStrategy,
  GroupRowsState,
} from '@infinite-table/infinite-react';
import { columns, Employee } from './employee-columns';

const groupRowsBy: DataSourcePropGroupRowsBy<Employee> = [
  {
    field: 'department',
  },
  {
    field: 'companyName',
  },
];

const domProps = {
  style: { flex: 1 },
};

const groupRowsState = new GroupRowsState({
  expandedRows: [],
  collapsedRows: true,
});

export default function App() {
  const [groupRenderStrategy, setGroupRenderStrategy] =
    React.useState<InfiniteTablePropGroupRenderStrategy>(
      'multi-column'
    );

  const [hideEmptyGroupColumns, setHideEmptyGroupColumns] =
    React.useState(true);
  return (
    <div
      style={{
        display: 'flex',
        flex: 1,
        color: 'var(--infinite-row-color)',
        flexFlow: 'column',
        background: 'var(--infinite-background)',
      }}>
      <div style={{ padding: 10 }}>
        <label>
          <input
            type="checkbox"
            checked={hideEmptyGroupColumns}
            onChange={() => {
              setHideEmptyGroupColumns(
                !hideEmptyGroupColumns
              );
            }}
          />
          Hide Empty Group Columns (make sure all
          `Department` groups are collapsed to see it in
          action)
        </label>
      </div>
      <DataSource<Employee>
        data={dataSource}
        primaryKey="id"
        defaultGroupRowsState={groupRowsState}
        groupRowsBy={groupRowsBy}>
        <InfiniteTable<Employee>
          domProps={domProps}
          hideEmptyGroupColumns={hideEmptyGroupColumns}
          groupRenderStrategy={'multi-column'}
          columns={columns}
          columnDefaultWidth={250}
        />
      </DataSource>
    </div>
  );
}

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

Single group column

You can group by multiple fields, yet only render a single group column. To choose this rendering strategy, specify groupRenderStrategy property to be single-column.

In this case, you can’t override the group column for each group field, as there’s only one group column being generated. However, you can specify a groupColumn property to customize the generated column.

Single-column group render strategy
Fork
import * as React from 'react';
import {
  InfiniteTable,
  DataSource,
  DataSourcePropGroupRowsBy,
  InfiniteTableColumnRenderValueParam,
} from '@infinite-table/infinite-react';
import { columns, Employee } from './columns';

const groupRowsBy: DataSourcePropGroupRowsBy<Employee> = [
  {
    field: 'age',
  },
  {
    field: 'companyName',
  },
];

const groupColumn = {
  header: 'Grouping',
  width: 250,
  // in this function we have access to collapsed info
  // and grouping info about the current row - see rowInfo.groupBy
  renderValue: ({
    value,
    rowInfo,
  }: InfiniteTableColumnRenderValueParam<Employee>) => {
    const groupBy = rowInfo.groupBy || [];
    const collapsed = rowInfo.collapsed;
    const groupField = groupBy[groupBy.length - 1];

    if (groupField === 'age') {
      return `🥳 ${value}${collapsed ? ' 🤷‍♂️' : ''}`;
    }

    return `🎉 ${value}`;
  },
};

export default function App() {
  return (
    <DataSource<Employee>
      data={dataSource}
      primaryKey="id"
      groupRowsBy={groupRowsBy}>
      <InfiniteTable<Employee>
        groupRenderStrategy="single-column"
        groupColumn={groupColumn}
        columns={columns}
        columnDefaultWidth={150}
      />
    </DataSource>
  );
}

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

Note

If groupColumn is specified to an object and no groupRenderStrategy is passed, the render strategy will be single-column.

groupColumn can also be a function, which allows you to individually customize each group column - in case the `multi-column` strategy is used.

Inline group column

When inline group rendering is used (groupRenderStrategy=“inline”), the columns bound to the corresponding group by fields are used for rendering, so no group columns are generated. This way of rendering groups is only recommended when you’re sure you have small groups (smaller than the number of rows visible in the viewport).