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

jattac.libs.web.responsive-table

v0.18.0

Published

A fully responsive, customizable, and lightweight React table component with a modern, mobile-first design and a powerful plugin system.

Downloads

2,434

Readme

ResponsiveTable

Enterprise-Grade React Data Grid Component

ResponsiveTable is a high-performance, type-safe React component designed for complex data visualization. It provides seamless layout transitions between desktop-optimized tabular displays and mobile-optimized card views, ensuring data integrity and accessibility across all device form factors.

Core Capabilities

  • Dynamic Layout Orchestration: Automated transformation between standard table structures and mobile-optimized interfaces based on configurable breakpoints.
  • Extensible Architecture: A robust plugin system for implementing sorting, filtering, row selection, and asynchronous data fetching.
  • Intelligent Layout Scaling: Automated recalculation of footer colSpan ranges to maintain structural alignment when columns are programmatically excluded.
  • Performance Optimized: An atomized internal architecture that decouples state management from rendering, minimizing re-render cycles.
  • Type Safety: Comprehensive TypeScript definitions for predictable implementation and robust development workflows.

Installation

npm install jattac.libs.web.responsive-table jattac.libs.web.zest-textbox react-icons

Table of Contents


Built-in Filter

Enable the search box with one prop. A clear (×) button appears automatically when the field has text.

Client-side — filters the in-memory data array and highlights matches:

<ResponsiveTable
  data={rows}
  columnDefinitions={columns}
  filterProps={{ showFilter: true }}
/>

Server-side — when dataSource is present, server mode is automatic. The table resets to page 1 and calls your fetch function with the current filter string on every change:

<ResponsiveTable
  dataSource={async ({ page, pageSize, filter }) =>
    api.getUsers({ page, pageSize, search: filter })
  }
  columnDefinitions={columns}
  filterProps={{ showFilter: true }}
/>

To force client-side filtering even with a dataSource, pass mode: 'client'.


Delightful Data Fetching: Smart Data Source

The dataSource pattern makes handling large datasets, server-side sorting, filtering, and infinite scroll completely painless. You provide the fetch logic; the table handles bookkeeping.

Pagination only

<ResponsiveTable
  dataSource={async ({ page, pageSize }) => {
    const users = await api.getUsers({ page, pageSize });
    return users; // hasMore is auto-detected from page size
  }}
  columnDefinitions={columns}
/>

Pagination + sorting + filtering

<ResponsiveTable
  dataSource={async ({ page, pageSize, sort, filter }) =>
    api.getUsers({
      page,
      limit: pageSize,
      sortBy: sort?.columnId,
      order: sort?.direction,
      search: filter,
    })
  }
  columnDefinitions={columns}
  sortProps={{ initialSortColumn: 'name' }}
  filterProps={{ showFilter: true }}
/>

With total count (accurate hasMore)

Return { items, totalCount } instead of a plain array and the table derives hasMore precisely:

dataSource={async ({ page, pageSize }) => {
  const { data, total } = await api.getUsers({ page, pageSize });
  return { items: data, totalCount: total };
}}

Basic Implementation

The following example demonstrates a standard implementation of the ResponsiveTable component:

import React from 'react';
import ResponsiveTable from 'jattac.libs.web.responsive-table';

const data = [
  { id: 1, name: 'Administrative User' },
  { id: 2, name: 'Standard User' }
];

const columns = [
  { displayLabel: 'Identifier', cellRenderer: (row) => row.id },
  { displayLabel: 'User Name', cellRenderer: (row) => row.name },
];

const App = () => (
  <ResponsiveTable 
    data={data} 
    columnDefinitions={columns} 
  />
);

Handling Interactive Elements

When using the onRowClick prop, clicking any element within a row will trigger the callback. To prevent this when clicking buttons or other interactive elements, use the data-rt-ignore-row-click attribute.

const columns = [
  {
    displayLabel: 'Actions',
    cellRenderer: (row) => (
      <button 
        data-rt-ignore-row-click 
        onClick={() => handleDelete(row.id)}
      >
        Delete
      </button>
    )
  }
];

For a deep dive into more complex scenarios, see the Handling Interactive Elements Guide.


Expandable Rows

Pass expandRowRenderer to reveal arbitrary content below any row. Each expandable row gets a chevron in a dedicated left column (▶ collapsed, ▾ expanded). Returning null or undefined for a row suppresses its toggle entirely — that row renders flat with no visual affordance.

<ResponsiveTable
  data={orders}
  columnDefinitions={columns}
  expandRowRenderer={(order) => <OrderLineItems orderId={order.id} />}
/>

Selectively expandable — only rows where the renderer returns content get a toggle:

expandRowRenderer={(order) =>
  order.lineItems.length > 0
    ? <OrderLineItems order={order} />
    : null
}

Using rowIndex — the renderer receives both the row object and its current display-order index. Useful for position-based formatting, alternating detail styles, or correlating with a parallel index-aligned array:

expandRowRenderer={(row, rowIndex) => (
  <DetailPanel row={row} zebra={rowIndex % 2 === 0} />
)}

rowIndex is the display-order index (post-sort, post-filter) — it changes when the user re-sorts. For stable data correlation across renders, use the row's own identifier field (row.id, etc.).

Customising the chevron — override color, size, or any other style via expandChevronClassName. Do not override transform or transition — these drive the rotation animation.

// Accent color from your design system
<ResponsiveTable
  expandChevronClassName="my-brand-chevron"
  expandRowRenderer={(row) => <Detail row={row} />}
  ...
/>
/* your stylesheet */
.my-brand-chevron {
  color: #7c3aed;   /* purple accent */
  font-size: 2rem;
}

Behaviour

  • Chevron sits in a dedicated 2rem left column — not as an overlay or pseudo-element — keeping the data columns aligned.
  • Idle: chevron at 25% opacity, rotates right (-90deg). Quiet, non-intrusive.
  • Hover: chevron smooths to 60% opacity, faint border accent on the row.
  • Expanded: chevron rotates down (0deg), full opacity. A toggle bar slides in (0→2rem) at the top of the detail pane.
  • Greeting animation: on mount, chevrons pop in with a staggered multi-pulse wave (2.2s), then settle to idle. Plays once per component lifecycle.
  • Expand and onRowClick coexist safely — the chevron carries data-rt-ignore-row-click.
  • Works identically in both desktop (table row) and mobile (card) layouts.

For the full feature reference — expansion state keying, lazy mounting, keyboard accessibility, dataSource compatibility, common patterns, CSS customization, and pitfalls — see the Row Expansion and Collapse Guide.


Row Interaction & Feedback

When onRowClick or selectionProps is provided, the table delivers tactile interaction feedback at every phase of the click:

| Phase | Desktop | Mobile | | :--- | :--- | :--- | | Hover | Subtle background lightening | Card lifts 4px with enhanced shadow | | Press (:active) | Background deepens — confirms the press registered | Card compresses back to 1px lift | | Release / Selected | Background sweeps to the selection tint (150ms transition) | Same tint + primary-color left border | | Keyboard focus | 2px primary-color outline (:focus-visible only — not shown on mouse click) | Same |

Rationale — each phase is distinct so users receive unambiguous confirmation that their input was received, without animations that feel slow or decorative. The :active state is the most critical: it fires in the 80–150ms window of the press itself, before any state change, so even users on slow networks feel an immediate response.

Keyboard navigation — all clickable rows and cards have tabIndex=0 and a :focus-visible ring. Tab through rows; press Enter or Space to trigger onRowClick.

Combining with onRowClick and selection:

<ResponsiveTable
  data={employees}
  columnDefinitions={columns}
  onRowClick={(employee) => navigate(`/employees/${employee.id}`)}
  selectionProps={{
    rowIdKey: 'id',
    mode: 'multiple',
    onSelectionChange: (selected) => setSelected(selected),
  }}
/>

Best practices

  • Always pair onRowClick with a visible hover state cue (the default cursor change handles this automatically).
  • If rows contain buttons or links, use data-rt-ignore-row-click on those elements so inner interactions don't also trigger the row handler.
  • For selection, always provide rowIdKey pointing to a stable unique field — this ensures expand state and selection state both survive sort/filter changes.

Loading States & Animations

Control skeleton loaders and entrance animations with animationProps:

<ResponsiveTable
  data={rows}
  columnDefinitions={columns}
  animationProps={{ isLoading: isFetching, animateOnLoad: true }}
/>

| Prop | Type | Description | | :--- | :--- | :--- | | isLoading | boolean | Shows a skeleton loader while true. Merges with internal dataSource loading state. | | animateOnLoad | boolean | Animates rows in on initial mount with a staggered entrance effect. |


Documentation Directory

The following technical documentation provides comprehensive implementation guidance:

  1. Technical Implementation Guide - Practical examples for core features, including infinite scroll and plugin integration.
  2. Functional Capabilities - A high-level overview of the component's feature set.
  3. API Reference - Technical specifications for props, interfaces, and type definitions.
  4. Configuration Specification - Detailed guidance on performance tuning and UI customization.
  5. Architecture and Contribution Guide - Internal system design and development environment setup.
  6. Handling Interactive Elements - Guide on preventing row click bubbling for buttons and custom components.
  7. Row Expansion and Collapse - Comprehensive guide for expandable row detail panels.
  8. Recommendations and Pitfalls - Best practices, anti-patterns, and ESM/CJS module compatibility guide.

Next Step: Review the Technical Implementation Guide