Customizing your DataGrid component with Tailwind CSS

By raduยท

Customizing your DataGrid component with Tailwind CSS
We haven't spoken about this very much, but Infinite Table does offer you very powerful ways to customize the structure of your component. After all, we're a React-first DataGrid, so the component and composition patterns it offers should feel at home in a React app.
Default structure of InfiniteTable
<DataSource>
  <InfiniteTable />
</DataSource>

Customizing the nesting of the InfiniteTable component#

However, be aware that you the <InfiniteTable /> component doesn't have to be a direct child of the <DataSource /> component. The <DataSource /> component doesn't actually render anything, but its job is to load, process and prepare the data in a way that <InfiniteTable /> understands and can display. And actually you can use the DataSource context to gain access to the data yourself.
InfiniteTable can be nested anywhere inside the <DataSource /> component
<DataSource>
  <h1>Your DataGrid</h1>
  <App>
    <InfiniteTable />
  </App>
</DataSource>
Inside the <DataSource /> component you can use the DataSource-provided context via the useDataSourceState hook that our component exposes.

Choosing what to render#

Besides the flexibility of nesting your DataGrid component anywhere in your app, we also offer you the ability to choose what parts of the DataGrid you want to render and where.
Let's suppose you want to show the header after the body of the DataGrid or choose to insert something in between. That should be easy, right? It is with Infinite! - but try to do that with the other commercial DataGrids out there!
View Mode
Fork
import {
  InfiniteTable,
  DataSource,
  InfiniteTableColumn,
  DataSourceGroupBy,
  components,
  useDataSourceState,
} from '@infinite-table/infinite-react';
import * as React from 'react';

const { CheckBox } = components;

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 columns: Record<string, InfiniteTableColumn<Developer>> = {
  age: {
    field: 'age',
    header: 'Age',
    type: 'number',
    defaultWidth: 100,
    renderValue: ({ value }) => value,
  },
  salary: {
    field: 'salary',
    type: 'number',
    defaultWidth: 210,
  },
  currency: { field: 'currency', header: 'Currency', defaultWidth: 100 },
  preferredLanguage: {
    field: 'preferredLanguage',
    header: 'Programming Language',
  },

  canDesign: {
    defaultWidth: 135,
    field: 'canDesign',
    header: 'Design Skills',
    renderValue: ({ value }) => {
      return (
        <div style={{ display: 'flex', alignItems: 'center' }}>
          <CheckBox
            defaultChecked={value === null ? null : value === 'yes'}
            domProps={{
              style: {
                marginRight: 10,
              },
            }}
          />
          {value === null ? 'Some' : value === 'yes' ? 'Yes' : 'No'}
        </div>
      );
    },
  },
  country: {
    field: 'country',
    header: 'Country',
  },
  firstName: { field: 'firstName', header: 'First Name' },
  stack: { field: 'stack', header: 'Stack' },

  city: {
    field: 'city',
    header: 'City',
    renderHeader: ({ column }) => `${column.computedVisibleIndex} City`,
  },
};

export default function App() {
  const groupBy: DataSourceGroupBy<Developer>[] = React.useMemo(
    () => [
      {
        field: 'country',
      },
      { field: 'stack' },
    ],
    [],
  );

  return (
    <div className="flex flex-col h-[80vh] text-foreground bg-background">
      <DataSource<Developer>
        data={dataSource}
        primaryKey="id"
        defaultGroupBy={groupBy}
      >
        <h1 className="text-2xl">Your DataGrid</h1>
        <AppGrid />
      </DataSource>
    </div>
  );
}

function AppGrid() {
  const { dataArray } = useDataSourceState();
  return (
    <div className="flex-1 flex flex-col gap-1 ">
      <InfiniteTable<Developer>
        groupRenderStrategy="single-column"
        defaultActiveRowIndex={0}
        columns={columns}
        columnDefaultWidth={150}
      >
        <div className="flex flex-1 flex-row">
          <div className="flex flex-1 flex-col">
            <InfiniteTable.Body />
            <div className="text-foreground text-lg p-3">
              Showing {dataArray.length} rows
            </div>
            <InfiniteTable.Header />
          </div>
          <InfiniteTable.GroupingToolbar orientation="vertical" />
        </div>
      </InfiniteTable>
    </div>
  );
}

const dataSource = () => {
  return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers100')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};
As demoed above, the good part is that you can very easily add additional elements to your structure and have the grouping toolbar displayed on the side, vertically.
Example structure for vertical grouping toolbar
<DataSource>
  <InfiniteTable>
    <div className="flex flex-1 flex-row">
      <div className="flex flex-1 flex-col">
        <InfiniteTable.Header />
        <InfiniteTable.Body />
      </div>
      <InfiniteTable.GroupingToolbar orientation="vertical" />
    </div>
  </InfiniteTable>
</DataSource>
In the example above, try dragging the header of the age column onto the GroupingToolbar to add grouping by age.