Tanstack: how to add tables to your React app
Published: 2023-05-09 23:45:42

by [Eli Musa](https://blog.openreplay.com/authors/eli-musa)

<blockquote><em>
Attention all frontend enthusiasts and curious minds! Are you tired of struggling to create React tables that look good and perform better? Well, have no fear because Tanstack Table is here, and this article will teach you all about it!</em>
</blockquote>

A [Tanstack table](https://tanstack.com/table/v8) is a workhorse built to filter, sort, group, aggregate, paginate, materialize, and display massive datasets. It offers many improved features, such as performance, server-side rendering (SSR) support, new hooks, and a more modern, flexible API. Its headless design doesn't ship with components and markup styles, giving us full control over markup and styles. In this article, we will focus on how to start adding and styling our ReactJS tables using Tanstack Table. So, let's dive in and see what Tanstack Table offers!

## Preview of The Table API

The Table API is a collection of functions and objects used to build and render tables. Below are the library adapters to choose from.

- [React Table](https://tanstack.com/table/v8/docs/adapters/react-table)
- [Solid Table](https://tanstack.com/table/v8/docs/adapters/solid-table)
- [Svelte Table](https://tanstack.com/table/v8/docs/adapters/svelte-table)
- [Vue Table](https://tanstack.com/table/v8/docs/adapters/vue-table)
- [Vanilla JS/TS](https://tanstack.com/table/v8/docs/adapters/vanilla)

Here are some of the key features of the Tanstack React Table API:

1. `columns`: This is an array of objects that define the table's columns. Each object should contain at least a Header property, which is the label for the column, and an accessor property, which is a function that returns the value for a column based on the data.

2. `data`: The data property is an array of objects representing the table's rows. Each object should have properties corresponding to the accessor functions defined in the columns array.

3. `useReactTable`: This hook creates a new table instance and returns the necessary functions and objects to render it. The functions include getTableProps, getTableBodyProps, headerGroups, and rows.

4. `getTableProps`: The getTableProps function is a function that returns a set of props that should be applied to the `<table>` element.

5. `getTableBodyProps`: The getTableBodyProps function is a function that returns a set of props that should be applied to the `<tbody>` element.

6. `headerGroups`: The headerGroups property is an array of objects that represent the header groups of the table. Each object contains a headers property, an array of the columns in that group.

7. `rows`: The rows property is an array of objects representing the table's rows. Each object contains a cells property, an array of objects representing the cells in that row.

8. `prepareRow`: This function prepares a row object for rendering by applying any necessary styles or props.


##  Installing and Importing Tanstack Table

Before we dig into the API, it's important to note that we will be using Typescript with React, so when initializing your project, choose Typescript as the preferred language. This can easily be done using [NextJS](https://nextjs.org/docs) or [ViteJS](https://vitejs.dev/).

Let's get set up! With our terminal pointing to our project folder, we can run the following command to install the Tanstack adapter for ReactJS.

```bash
npm install @tanstack/react-table
```

![-](https://blog.openreplay.com/images/tanstack--how-to-add-tables-to-your-react-app/images/ntEva2S.png)

Next, we have to import it to use it. Quick, in our project working directory, navigate to our source folder, create a new folder, and name it `components`. In that folder, create a file, name it `tanstack.tsx`, and then add the following code.

```typescript
import {
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";
```

The code imports two of the most important functions from the library: `createColumnHelper` and `useReactTable`.

-. `createColumnHelper` is a helper function used to create column definitions for our table.
-. `useReactTable` is the main hook function that we'll use to generate a table instance based on our data and column definitions.

Here's the structure for our working directory.

![-](https://blog.openreplay.com/images/tanstack--how-to-add-tables-to-your-react-app/images/cdwcF60.png)


## Preparing the Data
We will save our data in JSON format, so if you don't already have it, we have a copy [available](https://drive.google.com/file/d/1d2anFe6E-G9mN_jpXiv8x9HKSoKvljA4/view?usp=drivesdk). To use it in the application, navigate to the components folder, create a new file named `data.json`, and paste the data as an array of objects.

![-](https://blog.openreplay.com/images/tanstack--how-to-add-tables-to-your-react-app/images/EUc8mke.png)

We must import the file into our React component `tanstack.tsx`.


`tanstack.tsx`
```typescript
import {
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from '@tanstack/react-table'

import { defaultData } from './data.json';
```

Now that we have everything we need, we can define our table schema and create the table.

## Setting Up Tables with Tanstack Table
In this section, we will use most of the functions available in the Table API. Let's jump in and start defining our table. The first step is to create an object with the properties we need from our data. In TypeScript, we can do this by defining a TypeScript type object. In our case, let's call it `Student`. This will later indicate that it holds an array defined as `Student`.

`tanstack.tsx`
```typescript
type Student = {
  Application_No: number;
  Name: string;
  Father_Name: string;
  DOB: string;
};
```

We defined a TypeScript type `Student` that represents an object with properties such as Application No, Name, Father Name, and DOB.

Next, we'll create a new instance of the `createColumnHelper` function, which we'll use to define the table columns.


`tanstack.tsx`
```typescript
const columnHelper = createColumnHelper<Student>();
```

We will use the `createColumnHelper()` function to create a `columnHelper` object that we'll use to define a `columns` object.

We must create the `columns` object to complete our table schema. It should contain an array of objects, each representing a column in the table. We create each object using the `columnHelper.accessor()` function, which returns an object with configuration options for the corresponding column.

`tanstack.tsx`
```typescript
const columns = [
  columnHelper.accessor("Application_No", {
    header: "Registration No",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("Name", {
    header: "Name",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("Father_Name", {
    header: "Father Name",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("DOB", {
    header: "Date of Birth",
    cell: (info) => info.getValue(),
  }),
];
```

The `accessor()` function of the` columnHelper` specifies the data accessor for each column, which extracts the value of a property from the row of data in the `data.json` file.

We have successfully defined our table columns; our code should be like the one below.

`tanstack.tsx`
```typescript
import {
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";

import defaultData from "./data.json";

type Student = {
  Application_No: number;
  Name: string;
  Father_Name: string;
  DOB: string;
};

const columnHelper = createColumnHelper<Student>();

const columns = [
  columnHelper.accessor("Application_No", {
    header: "Registration No",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("Name", {
    header: "Name",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("Father_Name", {
    header: "Father Name",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("DOB", {
    header: "Date of Birth",
    cell: (info) => info.getValue(),
  }),
];
```

The next section will determine the final table output. In our `tanstack.tsx` file, below the`columns` object, we will define a React functional component named Table. This function will render a table using the `useReactTable` hook we imported earlier.

`tanstack.tsx`
```typescript
function Table() {
  const [data, setData] = useState<Student[]>(defaultData);

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

  return <></>;
}
```

The `Table` function starts by initializing the data state to an array of `Student` objects using the `useState` hook, where each `Student` object will represent a table row.

Next, our `useReactTable` hook is called to create a table object. The hook takes an object with three properties:

- `data`: An array of data representing the table's rows.
- `columns`: An array of objects representing the table's columns.
- `getCoreRowModel`: A function that returns a row model that specifies how the rows should be displayed.

The `table` object will render our table in the return statement of the `Table` function. 

Before rendering our table, it's key that we know what the `<th>`, `<td>`, and `<tr>` elements represent in tables.

![-](https://blog.openreplay.com/images/tanstack--how-to-add-tables-to-your-react-app/images/3aEYOLx.png)

`<th>`: This element defines a header cell in a table. A header cell is typically used to label the columns or rows of the table and is displayed in bold to differentiate it from the other cells.

`<td>`: This element defines a standard cell in a table. Standard cells contain the main content of the table and are usually displayed with normal text formatting.

`<tr>`: This element defines a row in a table. A row comprises one or more cells; each cell is defined using either a `<th>` or `<td>` element.

By combining these elements, we can create tables that display information in a structured and organized way. 

Return to our `Table` component and add the following code to our return statement.

`tanstack.tsx`
```typescript
return (
  <div>
    <table>
      <thead>
        {table.getHeaderGroups().map((headerGroup) => (
          <tr key={headerGroup.id}>
            {headerGroup.headers.map((header) => (
              <th key={header.id}>
                {header.isPlaceholder
                  ? null
                  : flexRender(
                      header.column.columnDef.header,
                      header.getContext()
                    )}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody>
        {table.getRowModel().rows.map((row) => (
          <tr key={row.id}>
            {row.getVisibleCells().map((cell) => (
              <td key={cell.id}>
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  </div>
);
```

In the return section, we render the table using the data and columns defined earlier. We start by creating a `<div>` element that contains a `<table>` element. Inside the `<table>` is an `<thead>` element containing rows with table headers.
    
For each header group returned by the `table.getHeaderGroups()`, we used the map method to iterate over the headers and created a `<th>` element for each one. If the header in place is a placeholder, null is returned; if not, the `flexRender` function is used to render the header element.

The next section is the `<tbody>` element, which contains rows with table cells. For each row in the table, we used the map method to iterate over the cells and created a `<td>` element for each one. Inside each `<td>`, the `flexRender` function is used to render the cell element.

Let's not forget to import our `Table` component to our root component.

```typescript
import Table from "@/components/tanstack";

export default function Home() {
  return (
    <>
      <Table />
    </>
  );
}
```

Let's run our project and check the rendered table in our browser. 

![-](https://blog.openreplay.com/images/tanstack--how-to-add-tables-to-your-react-app/images/kpyfQo9.png)


<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>



## Styling the Tanstack Table
Our table is now functional, but lacks visual appeal. To style it, we'll use [Styled-Components](https://styled-components.com/), which offers a CSS-in-JS approach that enables us to write structured and readable CSS code

We recommend checking their documentation if you have not been using Styled Components. We only need two styled components, `TableContainer` and `StyledTable`. `TableContainer` defines a div element with CSS styles applied as our table container.

Since Styled Components use regular CSS syntax to define styles, our `StyledTable` component will use `th` and `td` CSS selectors to target the `<th>` and `<td>` elements, respectively. 

In the `styles` folder, let's create a new `tableStyles.ts` file; here we will create all our required table styles.

`/styles/tableStyle.ts`
```typescript
import styled from "styled-components";

export const TableContainer = styled.div`
  position: relative;
  left: 10%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 14px;
  max-width: 800px;
`;

export const StyledTable = styled.table`
  width: 100%;
  border-collapse: collapse;
  margin-top: 20px;
  font-size: 0.9em;

  th {
    background-color: slategray;
    color: white;
    padding: 5px;
    border: 1px solid #ddd;
    text-align: left;
  }

  td {
    background-color: hsl(240, 50%, 90%);
    padding: 5px;
    border: 1px solid #ddd;
    text-align: left;
  }

  tr:nth-child(even) td {
    background-color: hsl(240, 50%, 85%);
  }

  tr:hover td {
    background-color: #ddd;
  }
`;
```

The `tr:nth-child(even) td` selector applies a background color to every row of `<td>` elements, creating a striped effect. When a user hovers over a row, the `tr:hover td` selector applies a background color to the `<td>` element.

Next, we need to update our Table component with these styled-components. We will import and replace them with the respective `tsx` elements.

```typescript
import {
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";

import defaultData from "./data.json";
import { useState } from "react";
import { StyledTable, TableContainer } from "@/styles/tableStyle";

type Student = {
  Application_No: number;
  Name: string;
  Father_Name: string;
  DOB: string;
};

const columnHelper = createColumnHelper<Student>();

const columns = [
  columnHelper.accessor("Application_No", {
    header: "Registration No",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("Name", {
    header: "Name",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("Father_Name", {
    header: "Father Name",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("DOB", {
    header: "Date of Birth",
    cell: (info) => info.getValue(),
  }),
];

function Table() {
  const [data, setData] = useState<Student[]>(defaultData);

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

  return (
    <TableContainer>
      <StyledTable>
        <thead>
          {table.getHeaderGroups().map((headerGroup) => (
            <tr key={headerGroup.id}>
              {headerGroup.headers.map((header) => (
                <th key={header.id}>
                  {header.isPlaceholder
                    ? null
                    : flexRender(
                        header.column.columnDef.header,
                        header.getContext()
                      )}
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody>
          {table.getRowModel().rows.map((row) => (
            <tr key={row.id}>
              {row.getVisibleCells().map((cell) => (
                <td key={cell.id}>
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </StyledTable>
    </TableContainer>
  );
}
export default Table;
```

Congratulations! For making it this far, our final Table version is now styled. 

![-](https://blog.openreplay.com/images/tanstack--how-to-add-tables-to-your-react-app/images/anw66o9.png)


Now that the table looks great, you may want to check Tanstack's [documentation](https://tanstack.com/table/v8/docs/guide/introduction) for other features such as adding pagination and sorting to improve the table's usability further. They can help users navigate large data sets and make finding the information they need easier.

## Conclusion
The process presented here exemplifies a well-structured Tanstack React table. By using type annotations and following best practices for React development, the code ensures that the table is easily maintainable and extensible in the future.

It is essential to note that this is just one way to create a table in React. We may use alternative approaches depending on the application's specific requirements. By adopting the principles showcased, we can craft clean, maintainable code that effectively fulfills our needs.

## References
1. [Tanstack documentation](https://tanstack.com/table/v8/docs/guide/introduction)
2. [TanStack Table v8](https://github.com/TanStack/table)