How to create Dynamic Tables in React js
Tags: webdev, beginners, typescript
Published: 2023-02-14 19:11:11

Let's talk about Dynamic Tables which is a very common problem. We will do this without using any third party library. Let's see the problem we are dealing with. The issue is, we normally have many kind of data available in our application and we need to render that into the table. So instead of writing all kind of CSS and HTML over and over again, why not create a generic Table component and pass a JavaScript Object array to it. The Table Component will automatically render the Object Array. 

## Basic DynamicTable Component
So let's create a basic dynamic table component which accept two core props, one is the actual data to display in the table, second is the schema which tells have two basic information, one is `label` second is `key`, we can optionally pass `classes` or width kind of data. So our `DynamicTable` component props interface would look something like following 

```ts
interface TableProps {
  data: { [key: string]: any }[];
  schema: { label: string; key: string;width:string}[];
  onUpdate?: (id: string | number) => void;
  onDelete?: (id: string | number) => void;
}
```
Here you may notice we additionally passed two more functions into the props interface, one is `onUpdate` which is optional, second is `onDelete` which is also optional. 
The main reason for using these props is to tell the parent component is that specific row is requested to be updated or delete. These two functions are also a basic need when we have to update or delete a specific row level data. 

## Rendering the Table 

Now let's focus on the actual rendering process. As you may already guessed that we have to look into the schema table and render the data object. That will look basically something like following, 

```ts
  <div>
      
      <table className="table-auto w-full text-left overflow-x-auto">
        <thead
          className="bg-gray-800 text-white"
          onClick={() => setSelectedIndex(-1)}
        >
          <tr>
            {schema.map((col, index) => (
             
              <th key={index} className= {`px-4 py-2 `}>
                {col.label}
              </th>
            
            ))}
            {(onUpdate || onDelete) && <th className="px-4 py-2 w-52">Actions</th>}
          </tr>
        </thead>
        <tbody>
          {data.map((row, index) => (
            <tr
              key={index}
              className={`${
                index === selectedIndex ? "bg-gray-500" : ""
              } hover:bg-gray-500/75`}
              onClick={() => setSelectedIndex(index)}
            >
              {schema.map((col, colIndex) => (
                <td key={colIndex} className={`border px-4 py-2 `}>
                  {row[col.key]}
                </td>
              ))}
              {(onUpdate || onDelete) && (
                <td className="border px-4 py-2">
                  {onUpdate && (
                    <button
                      className="bg-blue-500 hover:bg-blue-400 text-white font-medium py-2 px-4 rounded-lg mr-2"
                      onClick={() => {
                        onUpdate(row.id);
                        
                      }}
                    >
                     <FaEdit/>
                    </button>
                  )}
                  {onDelete && (
                    <button
                      className="bg-red-500 hover:bg-red-400 text-white font-medium py-2 px-4 rounded-lg"
                      onClick={() => {
                        onDelete(row.id);
                       
                      }}
                    >
                      <FaTrash/>
                    </button>
                  )}
                </td>
              )}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
```

We had used the `React Icons` library and used the `Fa icons` for rendering the action buttons for `update` or `delete` actions. 

## Compete DynamicTable Component Code

Here is the complete component code for rendering the dynamic table according to above mentioned procedure. 

```ts
import React, { useState } from "react";
import { FaEdit, FaTrash } from "react-icons/fa";


interface TableProps {
  data: { [key: string]: any }[];
  schema: { label: string; key: string;width:string}[];
  onUpdate?: (id: string | number) => void;
  onDelete?: (id: string | number) => void;
}

const DynamicTable: React.FC<TableProps> = ({
  data,
  schema,
  onUpdate,
  onDelete,
}) => {
  const [selectedIndex, setSelectedIndex] = useState(-1);

  return (
    <div>
      
      <table className="table-auto w-full text-left overflow-x-auto">
        <thead
          className="bg-gray-800 text-white"
          onClick={() => setSelectedIndex(-1)}
        >
          <tr>
            {schema.map((col, index) => (
             
              <th key={index} className= {`px-4 py-2 `}>
                {col.label}
              </th>
            
            ))}
            {(onUpdate || onDelete) && <th className="px-4 py-2 w-52">Actions</th>}
          </tr>
        </thead>
        <tbody>
          {data.map((row, index) => (
            <tr
              key={index}
              className={`${
                index === selectedIndex ? "bg-gray-500" : ""
              } hover:bg-gray-500/75`}
              onClick={() => setSelectedIndex(index)}
            >
              {schema.map((col, colIndex) => (
                <td key={colIndex} className={`border px-4 py-2 `}>
                  {row[col.key]}
                </td>
              ))}
              {(onUpdate || onDelete) && (
                <td className="border px-4 py-2">
                  {onUpdate && (
                    <button
                      className="bg-blue-500 hover:bg-blue-400 text-white font-medium py-2 px-4 rounded-lg mr-2"
                      onClick={() => {
                        onUpdate(row.id);
                        
                      }}
                    >
                     <FaEdit/>
                    </button>
                  )}
                  {onDelete && (
                    <button
                      className="bg-red-500 hover:bg-red-400 text-white font-medium py-2 px-4 rounded-lg"
                      onClick={() => {
                        onDelete(row.id);
                       
                      }}
                    >
                      <FaTrash/>
                    </button>
                  )}
                </td>
              )}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default DynamicTable;
```

## Using this Component 

Now that we have our DynamicTable Component ready, you may want to know the basic example to use that component. Here we have basic usage example for this `DynamicTable` component. 

```ts
import React from "react";
import DynamicTable from "../Dynamic/DynamicTable";


const schema = [
  { key: "id", label: "ID",width:'32'},
  { key: "name", label: "Name",width:'32' },
  { key: "email", label: "Email",width:'64' },
  { key: "age", label: "Age" ,width: '32'},
];

const data = [
  { id: 1, name: "John Doe", email: "johndoe@example.com", age: 32 },
  { id: 2, name: "Jane Doe", email: "janedoe@example.com", age: 28 },
  { id: 3, name: "Bob Smith", email: "bobsmith@example.com", age: 35 },
];

function StoreOwnerTable() {
  
  const handleUpdate = (id: string | number) => {
    console.log(`Update row: ${id}`);
  };

  const handleDelete = (id: string | number) => {
    console.log(`Delete row: ${id}`);
  };

 



  return (
    <div className="container mx-auto ">
    
      {simpleUsers ? (
        <DynamicTable
          schema={schema}
          data={data}
          onUpdate={handleUpdate}
          onDelete={handleDelete}
        />
      ) : null}
      
    </div>
  );
}

export default StoreOwnerTable;
```