Overview

The HeadlessDataTable component is a flexible and customizable data table for React applications. It handles pagination and filtering, making it easy to present, navigate, and search through tabular data. With built-in support for custom headers and styles, it provides a user-friendly experience. Utilizing the useDataTable hook, it efficiently manages data operations and optimizes performance. Whether displaying product listings, user information, or financial data, this component streamlines data presentation and enhances the overall user interface. It saves development time, promotes data organization, and empowers developers to create intuitive and efficient data tables with minimal effort.

Installation

Before using these components, make sure you have already installed the required dependencies, including React and @locoworks/reusejs-toolkit-react-hooks. You can install the dependencies by running below command in terminal.

yarn add @locoworks/reusejs-react-data-table
or
npm install @locoworks/reusejs-react-data-table

External Dependencies:

HeadlessDataTable components depend on React and the useDataTable hook from the @locoworks/reusejs-toolkit-react-hooks package.

Importing:

To use the HeadlessDataTable component in your project, import it into your component.

import { HeadlessDataTable } from "@locoworks/reusejs-react-data-table"

Types/ Exported Components

HeadlessDataTable component uses TypeScript for type checking and define the HeadlessDataTableInterface interface to specify the prop types. The main exported component is HeadlessDataTable.

Example

NAMEGENDERAGEEMAILCONTACT DETAILSADDRESS
No results found.
Showing: 0/0Records.
Page : 1
import React, { useState, useEffect } from "react";
import { HeadlessDataTable } from "@locoworks/reusejs-react-data-table";

const Example = () => {
	const [userList, setUserLists] = useState([]);

	const fetchData = async (count: number) => {
		try {
			const response = await fetch(
				`https://randomuser.me/api/?results=${count}`,
			); // Replace with the API endpoint URL
			const data = await response.json();
			setUserLists(data.results); // Set the fetched data in the state
		} catch (error) {
			console.error("Error fetching data:", error);
		}
	};

	const userData: {
		Name: string;
		Gender: string;
		Age: number;
		Email: string;
		"Contact Details": string;
		Address: string;
	}[] = [];
	userList.forEach((user: any) => {
		const userObject = {
			Name: `${user.name.title} ${user.name.first} ${user.name.last}`,
			Gender: user.gender,
			Age: user.dob.age,
			Email: user.email,
			"Contact Details": user.cell,
			Address: `${user.location.city} ${user.location.state} ${user.location.country} ${user.location.postcode}`,
		};

		userData.push(userObject);
	});

	const tableHeader = [
		"Name",
		"Gender",
		"Age",
		"Email",
		"Contact Details",
		"Address",
	];

	const ShowRecordInfo = (
		totalPages: number,
		totalRecords: number,
		currentPage: number,
		itemsPerPage: number,
	) => {
		return (
			<>
				<div className="flex items-center">
					Showing:{" "}
					{currentPage < totalPages
						? `${currentPage * itemsPerPage}/${totalRecords}`
						: `${totalRecords}/${totalRecords}`}
					Records.
				</div>

				<div className="flex items-center">Page : {currentPage}</div>
			</>
		);
	};

	useEffect(() => {
		fetchData(50);
	}, []);

	return (
		<div className="flex flex-col items-center gap-x-3 justify-center py-10 mt-10 border rounded bg-gray-50">
			<HeadlessDataTable
				tableData={userData}
				itemsPerPage={5}
				customTableHeader={tableHeader}
				buttonClasses={"bg-gray-200 py-2 px-4 rounded-md text-gray-700 mb-10"}
				buttonContainerClasses={"flex justify-between mt-4"}
				showDetails={ShowRecordInfo}
				tableColumnClasses={"px-4 border border-gray-500"}
				tableContainerClasses={"flex flex-col px-10 w-full bg-white"}
				tableClasses={"w-full"}
				headingColumnClasses={"px-4 text-left border border-gray-500"}
				headingRowClasses={"bg-gray-300 "}
			/>
		</div>
	);
};

export default Example;

DataTable (Column Based Filter)

NAMEEMAILAGEEMAILCONTACT DETAILSADDRESS
No results found.
Showing: 0/0Records.
Page : 1/0
import React, { useState, useEffect } from "react";
import { HeadlessDataTable } from "@locoworks/reusejs-react-data-table";

const FilterDataTable = () => {
	const [userList, setUserLists] = useState([]);
	const [searchString, setSearchString] = useState<string>("");
	const [searchQueries, setSearchQueries] = useState<
		{ field: string; value: string }[]
	>([]);
	const [dropDownValue, setDropDownValue] = useState<string>("default");

	const fetchData = async (count: number) => {
		try {
			const response = await fetch(
				`https://randomuser.me/api/?results=${count}`,
			); // Replace with the API endpoint URL
			const data = await response.json();
			setUserLists(data.results); // Set the fetched data in the state
		} catch (error) {
			console.error("Error fetching data:", error);
		}
	};

	const userData: {
		name: string;
		gender: string;
		age: string;
		email: string;
		contact_details: string;
		address: string;
	}[] = [];
	userList.forEach((user: any) => {
		const userObject = {
			name: `${user.name.title} ${user.name.first} ${user.name.last}`,
			gender: user.gender,
			age: `${user.dob.age}`,
			email: user.email,
			contact_details: user.cell,
			address: `${user.location.country} ${user.location.postcode}`,
		};

		userData.push(userObject);
	});

	const tableHeader = [
		"name",
		"email",
		"age",
		"email",
		"contact_details",
		"address",
	];

	const ShowRecordInfo = (
		totalPages: number,
		totalRecords: number,
		currentPage: number,
		itemsPerPage: number,
	) => {
		return (
			<>
				<div className="flex items-center">
					Showing:{" "}
					{currentPage < totalPages
						? `${currentPage * itemsPerPage}/${totalRecords}`
						: `${totalRecords}/${totalRecords}`}
					Records.
				</div>

				<div className="flex items-center">
					Page : {currentPage}/{totalPages}
				</div>
			</>
		);
	};

	useEffect(() => {
		fetchData(50);
	}, []);

	return (
		<div className="flex flex-col items-center gap-x-3 justify-center py-10 mt-10 border rounded bg-gray-50">
			<div className="flex mx-10 items-center justify-between">
				<select
					className="flex py-2 text-xl px-4 rounded-md border border-gray-400 mb-10"
					value={dropDownValue}
					onChange={(e) => {
						setDropDownValue(e.target.value.toString());
					}}
				>
					<option value="default">Select Filter</option>
					{tableHeader.map((colunm: string, index: number) => {
						return (
							<option key={index} value={colunm}>
								{colunm}
							</option>
						);
					})}
				</select>
				<div className="flex justify-center items-center mb-10">
					<input
						onChange={(e) => {
							setSearchString(e.target.value);
							if (dropDownValue !== "default") {
								setSearchQueries([
									{ field: dropDownValue, value: e.target.value },
								]);
							}
						}}
						value={searchString}
						placeholder="Search Here..."
						className="flex py-2 px-4 border border-gray-400 rounded-md mx-10 bg-white"
					/>

					<button
						className="border border-gray-400 rounded-md py-2 px-4 bg-white"
						onClick={() => {
							setSearchString("");
							setSearchQueries([]);
							setDropDownValue("default");
						}}
					>
						clear
					</button>
				</div>
			</div>
			<HeadlessDataTable
				tableData={userData}
				itemsPerPage={5}
				customTableHeader={tableHeader}
				buttonClasses={"bg-gray-200 py-2 px-4 rounded-md text-gray-700 mb-10"}
				buttonContainerClasses={"flex justify-between mt-4"}
				showDetails={ShowRecordInfo}
				tableColumnClasses={"px-4 border border-gray-500"}
				tableContainerClasses={"flex flex-col px-10 w-full bg-white"}
				tableClasses={"w-full"}
				headingColumnClasses={"px-4 text-left border border-gray-500"}
				headingRowClasses={"bg-gray-300 "}
				queryObject={searchQueries}
				searchAll=""
			/>
		</div>
	);
};

export default FilterDataTable;

SearchTable (Search in whole table)

NAMEGENDERAGEEMAILCONTACT DETAILSADDRESS
No results found.
Showing: 1 to 5 of 0 results
import React, { useState, useEffect } from "react";
import { HeadlessDataTable } from "@locoworks/reusejs-react-data-table";

const FilterDataTable = () => {
	const [userList, setUserLists] = useState([]);
	const [searchString, setSearchString] = useState<string>("");

	const fetchData = async (count: number) => {
		try {
			const response = await fetch(
				`https://randomuser.me/api/?results=${count}`,
			); // Replace with the API endpoint URL
			const data = await response.json();
			setUserLists(data.results); // Set the fetched data in the state
		} catch (error) {
			console.error("Error fetching data:", error);
		}
	};

	const userData: {
		Name: string;
		Gender: string;
		Age: string;
		Email: string;
		"Contact Details": string;
		Address: string;
	}[] = [];
	userList.forEach((user: any) => {
		const userObject = {
			Name: `${user.name.title} ${user.name.first} ${user.name.last}`,
			Gender: user.gender,
			Age: `${user.dob.age}`,
			Email: user.email,
			"Contact Details": user.cell,
			Address: `${user.location.country} ${user.location.postcode}`,
		};

		userData.push(userObject);
	});

	const tableHeader = [
		"Name",
		"Gender",
		"Age",
		"Email",
		"Contact Details",
		"Address",
	];

	const ShowRecordInfo = (
		totalPages: number,
		totalRecords: number,
		currentPage: number,
		itemsPerPage: number,
	) => {
		return (
			<div className="flex items-center mt-10">
				Showing: {currentPage * itemsPerPage - (itemsPerPage - 1)} to{" "}
				{currentPage * itemsPerPage} of {totalRecords} results
			</div>
		);
	};

	useEffect(() => {
		fetchData(50);
	}, []);

	return (
		<div className="flex flex-col items-center gap-x-3 justify-center py-10 mt-10 border rounded bg-gray-50">
			<div className="flex justify-center items-center mb-10">
				<input
					onChange={(e) => {
						setSearchString(e.target.value);
					}}
					value={searchString}
					placeholder="Search Here..."
					className="flex py-2 px-4 border border-gray-400 rounded-md mx-10 bg-white"
				/>

				<button
					className="border border-gray-400 rounded-md py-2 px-4 bg-white"
					onClick={() => {
						setSearchString("");
					}}
				>
					clear
				</button>
			</div>
			<HeadlessDataTable
				tableData={userData}
				itemsPerPage={5}
				customTableHeader={tableHeader}
				buttonClasses={
					"bg-gray-200 py-2 px-4 rounded-md text-gray-700 mb-10 mx-4"
				}
				buttonContainerClasses={"flex justify-end relative -top-9"}
				showDetails={ShowRecordInfo}
				tableColumnClasses={"px-4 border border-gray-500"}
				tableContainerClasses={"flex flex-col px-10 w-full bg-white"}
				tableClasses={"w-full"}
				headingColumnClasses={"px-4 text-left border border-gray-500"}
				headingRowClasses={"bg-gray-300 "}
				queryObject={[]}
				searchAll={searchString}
			/>
		</div>
	);
};

export default FilterDataTable;

NestedSearchTable

NAMEGENDERAGEEMAILCONTACT DETAILSADDRESS
No results found.
Showing: 1 to 5 of 0 results
import React, { useState, useEffect } from "react";
import { HeadlessDataTable } from "@locoworks/reusejs-react-data-table";
import { ReuseInput } from "@locoworks/reusejs-react-input";
import { HeadlessButton } from "@locoworks/reusejs-react-button";

const FilterDataTable = () => {
	const [userList, setUserLists] = useState([]);
	const [searchQueries, setSearchQueries] = useState<
		{
			field: string;
			value: string;
		}[]
	>([]);
	const [nameField, setNameField] = useState("");
	const [emailField, setEmailField] = useState("");
	const [addressField, setAddressField] = useState("");

	const fetchData = async (count: number) => {
		try {
			const response = await fetch(
				`https://randomuser.me/api/?results=${count}`,
			); // Replace with the API endpoint URL
			const data = await response.json();
			setUserLists(data.results); // Set the fetched data in the state
		} catch (error) {
			console.error("Error fetching data:", error);
		}
	};

	const userData: {
		Name: string;
		Gender: string;
		Age: string;
		Email: string;
		"Contact Details": string;
		Address: string;
	}[] = [];
	userList.forEach((user: any) => {
		const userObject = {
			Name: `${user.name.title} ${user.name.first} ${user.name.last}`,
			Gender: user.gender,
			Age: `${user.dob.age}`,
			Email: user.email,
			"Contact Details": user.cell,
			Address: `${user.location.country} ${user.location.postcode}`,
		};

		userData.push(userObject);
	});

	const tableHeader = [
		"Name",
		"Gender",
		"Age",
		"Email",
		"Contact Details",
		"Address",
	];

	const ShowRecordInfo = (
		totalPages: number,
		totalRecords: number,
		currentPage: number,
		itemsPerPage: number,
	) => {
		return (
			<div className="flex items-center mt-10">
				Showing: {currentPage * itemsPerPage - (itemsPerPage - 1)} to{" "}
				{currentPage * itemsPerPage} of {totalRecords} results
			</div>
		);
	};

	const prepareSearchPayload = (
		name: string,
		email: string,
		address: string,
	) => {
		let namePayload;
		let emailPayload;
		let addressPayload;

		const queryObject: { field: string; value: string }[] = [];

		if (name !== "") {
			namePayload = { field: "Name", value: name };
			setSearchQueries([...searchQueries, namePayload]);
			queryObject.push(namePayload);
		}
		if (email !== "") {
			emailPayload = { field: "Email", value: email };
			queryObject.push(emailPayload);
		}
		if (address !== "") {
			addressPayload = { field: "Address", value: address };
			queryObject.push(addressPayload);
		}

		setSearchQueries(queryObject);
	};

	useEffect(() => {
		fetchData(50);
	}, []);

	return (
		<div className="flex flex-col items-center gap-x-3 justify-center py-10 mt-10 border rounded bg-gray-50">
			<div className="flex justify-center items-center mb-10">
				<ReuseInput
					placeholder="Search Name..."
					className="flex mx-4"
					onChange={(e) => {
						setNameField(e.target.value);
					}}
					value={nameField}
				/>
				<ReuseInput
					placeholder="Search Email..."
					className="flex mx-4"
					onChange={(e) => {
						setEmailField(e.target.value);
					}}
					value={emailField}
				/>
				<ReuseInput
					placeholder="Search Address"
					className="flex mx-4"
					onChange={(e) => {
						setAddressField(e.target.value);
					}}
					value={addressField}
				/>
				<HeadlessButton
					className="bg-blue-200 border border-blue-400 rounded px-3 py-1 mx-2"
					onClick={() => {
						prepareSearchPayload(nameField, emailField, addressField);
					}}
				>
					Search
				</HeadlessButton>
				<HeadlessButton
					className="bg-blue-200 border border-blue-400 rounded px-3 py-1"
					onClick={() => {
						setNameField("");
						setEmailField("");
						setAddressField("");
						setSearchQueries([]);
					}}
				>
					Clear Search
				</HeadlessButton>
			</div>
			<HeadlessDataTable
				tableData={userData}
				itemsPerPage={5}
				customTableHeader={tableHeader}
				buttonClasses={
					"bg-gray-200 py-2 px-4 rounded-md text-gray-700 mb-10 mx-4"
				}
				buttonContainerClasses={"flex justify-end relative -top-9"}
				showDetails={ShowRecordInfo}
				tableColumnClasses={"px-4 border border-gray-500"}
				tableContainerClasses={"flex flex-col px-10 w-full bg-white"}
				tableClasses={"w-full"}
				headingColumnClasses={"px-4 text-left border border-gray-500"}
				headingRowClasses={"bg-gray-300 "}
				queryObject={searchQueries}
				searchAll=""
			/>
		</div>
	);
};

export default FilterDataTable;

Props Table

Apologies for the oversight. Here is the corrected markdown table including the missing showDetails and customTableHeader:

PropTypeDescription
tableDataArray of ObjectAn array of objects representing the data for the table. Each object represents a row, and its properties represent columns.
itemsPerPageNumberAn integer representing the number of items to display per page. If set to 0 or not provided, all data will be displayed on a single page without pagination.
queryAllStringA string representing a global search query applied to the entire table. This allows users to search for a specific term across all columns.
searchQueryObjectArray of ObjectAn array of search query objects that allow filtering the data based on specific column values. Each object in the array should have two properties: field (string) - The name of the column to filter, value (string) - The value to search for in the specified column.
tableContainerClassesString/ObjectCustom CSS classes or styles to be applied to the container element that wraps the table. Accepts either a string of space-separated class names or an object of inline styles.
tableClassesString/ObjectCustom CSS classes or styles to be applied to the table element. Accepts either a string of space-separated class names or an object of inline styles.
tableRowClassesString/ObjectCustom CSS classes or styles to be applied to the table rows (tr elements). Accepts either a string of space-separated class names or an object of inline styles.
tableColumnClassesString/ObjectCustom CSS classes or styles to be applied to the table columns (td elements). Accepts either a string of space-separated class names or an object of inline styles.
headingRowClassesString/ObjectCustom CSS classes or styles to be applied to the heading row (tr element) of the table. Accepts either a string of space-separated class names or an object of inline styles.
headingColumnClassesString/ObjectCustom CSS classes or styles to be applied to the heading columns (th elements) of the table. Accepts either a string of space-separated class names or an object of inline styles.
buttonClassesString/ObjectCustom CSS classes or styles to be applied to the navigation buttons. Accepts either a string of space-separated class names or an object of inline styles.
buttonContainerClassesString/ObjectCustom CSS classes or styles to be applied to the container element that wraps the navigation buttons. Accepts either a string of space-separated class names or an object of inline styles.
showDetailsFunctionA function that receives totalPages, totalItems, currentPage, and itemsPerPage as arguments. This function can be used to display additional information about the pagination or any custom details based on the current state of the data table.
customTableHeaderArray of ObjectAn array of strings representing the table header. If not provided, the table header will be created from the tableData.

Note:

  • If you're looking to harness the power of the Simple DataTable with Pagination, or if you find the need for additional features like Search and Filter functionalities alongside Pagination, then the recommended choice is the HeadlessDataTable.
  • The HeadlessDataTable component seamlessly integrates the useDataTable hook from the @locoworks/reusejs-toolkit-react-hooks library. This hook efficiently manages pagination and various other functionalities, providing a range of properties for rendering the table and handling pagination. For a more in-depth understanding, please refer to the dedicated hook section.
  • Utilizing the HeadlessDataTable component automates the pagination of your tableData based on the