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
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,
<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.
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.
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;
Top comments (0)