npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

custom-table-search

v1.2.9

Published

A customizable, dynamic table component with advanced search, sorting, and pagination for React.

Readme

Custom Table Search

custom-table-search is a React component that provides a dynamic, customizable table with features like advanced search, sorting, pagination, and a grid view toggle. It’s ideal for applications needing flexible data exploration and presentation. Features

Customizable Columns: Define columns with options like labels, searchability, and sortability. Advanced Search and Filtering: Apply multiple conditions with SQL-like connectors (AND, OR). Sorting: Sort data by clicking column headers. Pagination: Control page size and navigate through records. Grid and Table Views: Toggle between grid and table views for versatile data display.

Features

  • Customizable Columns: Define table columns with labels, sortability, and search options.
  • Use customRenderer to display custom content like buttons or styled text in specific columns.
  • Advanced Search and Filtering: Apply multiple conditions with SQL-like connectors (AND, OR) for complex queries.
  • Sorting: Sort data by clicking on column headers.
  • Pagination: Control page size and navigate through data records.
  • Grid and Table Views: Toggle between grid and table views.
  • Action Buttons: Add custom action buttons (e.g., Edit, Delete, View) in rows to perform specific actions.

Installation

To install custom-table-search, run the following command:

npm install custom-table-search

Example 1: Static Data

This example uses local static data and showcases pagination, sorting, and action buttons.

import React, { useState, useEffect } from "react";
import TableCustom from "custom-table-search";
import "bootstrap/dist/css/bootstrap.min.css";

const sampleData = [
{ id: 1, name: "John Doe", email: "[email protected]", status: "Active" },
{ id: 2, name: "Jane Smith", email: "[email protected]", status: "Inactive" },
{ id: 3, name: "Alice Johnson", email: "[email protected]", status: "Active" },
// Add more data as needed
];

    const StaticDataPage = () => {
    const [data, setData] = useState([]);
    const [currentPage, setCurrentPage] = useState(1);
    const [pageSize, setPageSize] = useState(5); // Define setPageSize here
    const [totalRecords, setTotalRecords] = useState(sampleData.length);
    const customEntriesOptions = [5, 10, 20, 50];
    const customDefaultPageSize = 10;

    const columns = [
        { key: "id", label: "ID", sortable: true },
        { key: "name", label: "Name", sortable: true, searchable: true },
        { key: "email", label: "Email", sortable: true, searchable: true },
        {
          key: "status",
          label: "Status",
          textAlign: "center",
          customRenderer: (row) => (
            <span
                style={{
                    color: row.status === "Active" ? "green" : "red",
                }}
            >
                {row.status}
            </span>
        ),
        },
        {
          key: "actions",
          label: "Actions",
          textAlign: "center",
          customRenderer: (row) => (
            <button
                className="btn btn-primary"
                onClick={() => alert(`Action for ${row.name}`)}
            >
                Action
            </button>
          ),
        },
    ];


    // Pagination function
    const fetchPage = (page, size) => {
        setCurrentPage(page);
        setPageSize(size);
        const startIdx = (page - 1) * size;
        setData(sampleData.slice(startIdx, startIdx + size));
    };

    useEffect(() => {
        fetchPage(currentPage, pageSize);
    }, [currentPage, pageSize]);

    return (
            <div className="container mt-5">
                <h2>Static Data Table</h2>
                <TableCustom
                    data={data}
                    columns={columns}
                    gridViewEnabled={true}
                    entriesEnabled={true}
                    paginationEnabled={true}
                    searchEnabled={true}
                    currentPage={currentPage}
                    setCurrentPage={setCurrentPage}
                    fetchPage={fetchPage}
                    pageSize={pageSize}
                    setPageSize={setPageSize} // Pass setPageSize here
                    totalRecords={totalRecords}
                    entriesOptions={customEntriesOptions}
                    defaultPageSize={customDefaultPageSize}
                    bgColor="#111"
                    txtColor="#fff"
                    borderColor="#ddd"
                />
            </div>
        );
    };

    export default StaticDataPage;

Example 2: API Data

This example uses local static data and showcases pagination, sorting, and action buttons.

import React, { useRef, useState, useEffect } from "react";
import TableCustom from "custom-table-search";

import "bootstrap/dist/css/bootstrap.min.css";

const sampleData = [
{ id: 1, name: "John Doe", email: "[email protected]", status: "Active" },
{ id: 2, name: "Jane Smith", email: "[email protected]", status: "Inactive" },
{ id: 3, name: "Alice Johnson", email: "[email protected]", status: "Active" },
// Add more data as needed
];

const ApiDataExample = () => {
const tableRef = useRef();
const [data, setData] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(12);
const [totalRecords, setTotalRecords] = useState(sampleData.length);
// const customEntriesOptions = [5, 10, 20, 50];
// const customDefaultPageSize = 10;

const columns = [
    { key: "id", label: "ID", sortable: true },
    { key: "name", label: "Name", sortable: true, searchable: true },
    { key: "email", label: "Email", sortable: true, searchable: true },
    { key: "status", label: "Status", sortable: true, searchable: true },
];

// Function to fetch page data (simulating an API call)
const fetchPage = async (page, size) => {
    setCurrentPage(page);
    setPageSize(size);
    const startIdx = (page - 1) * size;
    const pagedData = sampleData.slice(startIdx, startIdx + size); // Simulate API data slice
    setData(pagedData);
    setTotalRecords(sampleData.length); // Set the total record count based on data length
};

useEffect(() => {
    const criteria = tableRef.current?.getSearchCriteria?.();
    const sort = tableRef.current?.getSortConfig?.();
    fetchPage(currentPage, pageSize, criteria, sort);
}, []);

return (
        <div className="container mt-5">
            <h2>API Data Table</h2>
            <TableCustom
                ref={tableRef}
                data={data}
                columns={columns}
                paginationEnabled={true}
                currentPage={currentPage}
                setCurrentPage={setCurrentPage}
                fetchPage={fetchPage} // Pass fetchPage to handle pagination
                pageSize={pageSize} // Current page size
                setPageSize={setPageSize} // Function to change page size
                totalRecords={totalRecords}
                // entriesOptions={customEntriesOptions}
                // defaultPageSize={customDefaultPageSize}
            />
        </div>
    );
};

export default ApiDataPage;

Example Explanation

- StaticDataTable:
    - Uses a local array (sampleData) and paginates by slicing the array based on currentPage and pageSize.
    - Action buttons for each row to demonstrate how custom buttons work within the table.
- ApiDataTable:
    - Fetches data from a mock API with pagination and page size passed as parameters.
    - Action buttons are also included here, demonstrating row-specific interactions with API-based data.

Props

Core Props

| Prop | Type | Default | Description | | ------------------- | ---------- | --------- | -------------------------------------------------------------------------------------- | | data | Array | [] | Array of data objects for each row. | | columns | Array | [] | Column configuration with options like label, searchability, and sortability. | | gridViewEnabled | Boolean | true | Enables toggle between grid and table view. | | entriesEnabled | Boolean | true | Enables page size dropdown to control entries per page. | | paginationEnabled | Boolean | true | Enables pagination controls for navigating pages. | | searchEnabled | Boolean | true | Enables column-specific search functionality. | | currentPage | Number | 1 | Current page number for pagination. | | setCurrentPage | Function | Required | Function to update the current page. | | fetchPage | Function | Required | Function to fetch data for the specified page and size, taking search/sort parameters. | | pageSize | Number | 12 | Number of records per page. | | setPageSize | Function | Required | Function to set the number of records per page. | | totalRecords | Number | 0 | Total number of records for accurate pagination. | | bgColor | String | #f8f9fa | Background color for the table. | | txtColor | String | #333333 | Text color for the table. |

Column Configuration

Each column object in the columns array can have the following properties:

| Column Property | Type | Default | Description | | --------------- | --------- | -------- | --------------------------------------------------------- | | key | String | Required | Unique identifier for the column. | | label | String | "" | Display name for the column header. | | sortable | Boolean | false | Allows sorting when true. | | searchable | Boolean | false | Enables search/filtering for this column. | | textAlign | String | "left" | Aligns text within the column (e.g., "center"). | | type | String | "text" | Input type for search fields (e.g., "text", "email"). |

Object Creted on Search and Filter

Example : For a search where the user is filtering by name and email columns with multiple conditions, the searchCriteria payload might look like this:

[
    {
        "column": "name",
        "conditions": [
        {
            "value": "John Doe",
            "operator": "LIKE",
            "localConnector": "OR"
        },
        {
            "value": "Alice Johnson",
            "operator": "LIKE"
        }
        ],
        "columnConnector": "AND"
    },
    {
        "column": "email",
        "conditions": [
        {
            "value": "[email protected]",
            "operator": "LIKE",
            "localConnector": "OR"
        },
        {
            "value": "[email protected]",
            "operator": "LIKE"
        }
        ],
        "columnConnector": null
    }
]

This object can be included in the body of an API request for server-side filtering. The API can interpret this payload to construct a query like:

WHERE (name LIKE 'John Doe' OR name LIKE 'Alice Johnson')
AND (email LIKE '[email protected]' OR email LIKE '[email protected]')

Parsing searchCriteria in Your Backend

On the server side, you’ll need to parse searchCriteria to generate a SQL or database query. For example:

-Loop through each column in the searchCriteria. -Apply each condition in the column, using localConnector to connect multiple conditions within a column. -Combine columns using columnConnector to achieve the full logical structure.

Example (in pseudo-code):

// Example pseudo-code for building a query string from searchCriteria
let query = "SELECT * FROM table WHERE ";
searchCriteria.forEach((columnObj, colIndex) => {
    const columnQuery = columnObj.conditions.map((cond, condIndex) => {
        return `${columnObj.column} ${cond.operator} '${cond.value}'` +
        (cond.localConnector ? ` ${cond.localConnector} ` : "");
    }).join("");

    query += columnQuery + (columnObj.columnConnector ? ` ${columnObj.columnConnector} ` : "");
});

Tips for Using the searchCriteria Object

  • SQL Injection Safety: If using SQL, ensure values are sanitized or parameterized to avoid SQL injection risks.
  • Flexible Conditions: With operator, localConnector, and columnConnector, you can build highly customizable queries, ideal for advanced filtering.
  • Testing: Test searchCriteria generation and API handling with various combinations to ensure robust handling of complex queries.

This searchCriteria object structure enables powerful and flexible search capabilities for your data, allowing precise filtering directly from the frontend component.

Example : Fetching data Search Inputs

{
    "page": 1,
    "size": 10,
    "searchCriteria": [
        {
        "column": "name",
        "conditions": [
            {
            "value": "John Doe",
            "operator": "LIKE",
            "localConnector": "OR"
            },
            {
            "value": "Alice Johnson",
            "operator": "LIKE"
            }
        ],
        "columnConnector": "AND"
        },
        {
        "column": "email",
        "conditions": [
            {
            "value": "[email protected]",
            "operator": "LIKE",
            "localConnector": "OR"
            },
            {
            "value": "[email protected]",
            "operator": "LIKE"
            }
        ],
        "columnConnector": null
        }
    ],
    "sortConfig": []
}

Example Usage in API Calls

Here’s how you might use the searchCriteria object as a payload for an API call to retrieve filtered data.

const fetchData = async (page, size, searchCriteria, sortConfig) => {
    try {
        const response = await fetch('/api/your-endpoint', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            page,
            size,
            searchCriteria,
            sortConfig
        })
        });
        const result = await response.json();
        // Handle the data from the response, e.g., update state
        setData(result.data);
        setTotalRecords(result.totalRecords);
    } catch (error) {
        console.error("Error fetching data:", error);
    }
};

Action Buttons

Action buttons (Edit, Delete, View) are added to each row by configuring the data prop with custom actions. Each button is attached to a function to handle its respective action:

const dataWithActions = data.map((row) => ({
...row,
actions: (
    <div className="d-flex justify-content-center">
        <button className="btn btn-primary btn-sm me-2" onClick={() => handleEdit(row)}>Edit</button>
        <button className="btn btn-danger btn-sm me-2" onClick={() => handleDelete(row)}>Delete</button>
        <button className="btn btn-info btn-sm" onClick={() => handleView(row)}>View</button>
    </div>
),
}));

These buttons perform specific functions when clicked, allowing the user to interact with each row in the table. Customize the icons and actions as needed.## Advanced Usage

Search Conditions and SQL-like Filters

  • Multiple Conditions per Column: Apply multiple conditions per column (e.g., LIKE, EQUAL, CONTAINS).
  • Logical Operators: Use AND or OR to connect conditions for complex queries.

Custom Actions

Add action buttons (e.g., Edit, Delete) by including an actions key in your data. Customize these buttons to handle events such as editing, deleting, or viewing details of a row.

Styling

The component uses standard Bootstrap styles. To customize further, apply your own CSS or Bootstrap overrides. Troubleshooting

Dependency Conflicts: Ensure you have compatible versions of react, react-dom, and react-bootstrap. Styling Issues: Ensure Bootstrap is included in your project or adjust styles as needed. Pagination Limits: Ensure totalRecords accurately reflects the number of entries for pagination to work correctly.

Troubleshooting

  • Dependency Conflicts: Ensure you have compatible versions of react, react-dom, and react-bootstrap.
  • Styling Issues: Ensure Bootstrap is included in your project or adjust styles as needed.
  • Pagination Limits: Ensure totalRecords accurately reflects the number of entries for pagination to work correctly.

Contributing

Feel free to submit issues or pull requests for bug fixes or enhancements. Contributions are welcome!

License

This project is licensed under the MIT License.