table-for-react
v1.0.1
Published
Framework-flexible React data table — optional Tailwind presets, semantic CSS hooks, and swappable primitives (Ant Design-friendly).
Maintainers
Readme
table-for-react
A React table/card component that stays easy to pair with Tailwind, Ant Design, your own CSS, or plain variables — without locking you into one styling system.
Do give me a star on github : Table for React
Demo you can try on local: Demo
Examples: Here
Install
npm install table-for-react react react-domOverall tabvle view

Card view with Grid layout

Card view with list layout

Column filter option using contains

column filter option using select

Select columns on runtime.

export specific columns as CSV

Render additional actions buttons

Quick patterns
1. Semantic CSS (works with vanilla CSS / any preprocessor)
Uses BEM-ish class names (smart-table, smart-table__th, …). Import the minimal layout stylesheet and override with --smart-table-* variables or plain CSS selectors.
import { SmartTable } from "table-for-react";
import "table-for-react/base.css";
<SmartTable appearance="minimal" columns={columns} data={rows} />;Tune colors / borders globally:
:root .smart-table {
--smart-table-border: var(--antd-color-border-secondary, #eee);
}2. Tailwind utility preset
Uses the bundled slot map tailwindClassNames (utilities as strings).
import { SmartTable } from "table-for-react";
<SmartTable appearance="tailwind" columns={columns} />;Ensure your Tailwind scanner sees the utilities (often already does if you @source package sources or reuse the preset in your outer app). Prefer adding the package folder to @source in Tailwind v4 if classes are purged unexpectedly — e.g. in your global CSS alongside @import "tailwindcss":
@import "tailwindcss";
@source "../../node_modules/table-for-react/src/**/*.{js,jsx}";Important for card view: with appearance="tailwind", also import table-for-react/base.css. Responsive grid/list layout for cards uses semantic classes (smart-table__card-grid, …); that keeps cards working even when Tailwind does not scan the library.
Per-slot replace (classNames):
<SmartTable
appearance="tailwind"
classNames={{
root: "w-full max-w-screen-lg rounded-xl border mx-auto shadow-sm",
searchInput: "rounded-md border-orange-400",
}}
/>Append more utilities everywhere without copying the full preset:
<SmartTable
appearance="tailwind"
appendClassNames={{
root: "backdrop-blur-sm",
pagination: "sticky bottom-0 bg-white pt-4",
}}
/>Build a reusable map with composeClassNames (chains cx() per slot; often used with appearance="minimal" and your Tailwind snippets):
import {
composeClassNames,
defaultClassNames,
} from "table-for-react";
const mySlots = composeClassNames(defaultClassNames, {
root: "rounded-2xl border-dashed shadow-none",
});
<SmartTable appearance="minimal" classNames={mySlots} />;3. Ant Design (component swap)
Plug in primitives so buttons/inputs/checkboxes render as Antd components:
import { Button, Checkbox, Input } from "antd";
import { SmartTable } from "table-for-react";
import "table-for-react/base.css";
<SmartTable
appearance="minimal"
components={{
Button: (p) => <Button {...p} size="middle" type="primary" />,
Input: (p) => <Input {...p} allowClear />,
Checkbox: ({ className, ...p }) => (
<Checkbox {...p} className={className} />
),
}}
/>If Ant Design and the preset both style buttons, replace those slots—for example classNames={{ exportPrimaryButton: "!min-h-0 rounded-md" }}—or appendClassNames to layer utilities.
Map Antd Typography/Table-level styling separately if you mirror their typography around the widget.
Slots API
Exported helpers:
| Export | Purpose |
|--------|---------|
| defaultClassNames | appearance="minimal" slot map |
| tailwindClassNames | Tailwind utility slot map |
| composeClassNames() | Concatenate partial slot overrides |
| mergeSlots(), appendSlots(), cx | Merge / concatenate class lists |
Inspect src/defaultClassNames.js / tailwindClassNames.js for slot keys (toolbar, th, pageButton, …).
Props (styling subset)
| Prop | Purpose |
|------|---------|
| appearance | "minimal" (default) semantic classes · "tailwind" preset |
| classNames | Partial slot overrides (replace preset per key) |
| appendClassNames | Concatenate utilities after classNames |
| components | { Button, Input, Checkbox } custom elements |
Sorting
- Column def:
{ key, label, sort: true }enables sorting for that column. sortAll: whentrue, every column is sortable; whenfalse, none. Ignoressorton columns when this is a boolean.- If
sortAllis omitted: use legacysortColumns={['key']}if non-empty, otherwise use each column’ssort. - Headers show ▲ and ▼; the active direction is emphasized. Rows are sorted client-side (including the current page when using server pagination).
Column value formats (format)
When a column has no render, format controls how row[column.key] is shown (table cells and the default card view). Sorting still uses the raw row[key] value.
{ type: "number", locale?, …Intl.NumberFormatOptions }— decimals, grouping, notation, etc.{ type: "currency", currency: "USD", locale?, currencyDisplay?, customSymbol?, minimumFractionDigits?, maximumFractionDigits? }—currencyDisplayis passed to Intl (symbol,narrowSymbol,code,name).customSymboloverrides the Intl currency prefix/suffix with a literal string plus formatted digits.{ type: "percentage", valueScale?: "ratio" | "percent", locale?, decimals? | minimumFractionDigits? / maximumFractionDigits? }—valueScale: "ratio"(default): store 0–1 (e.g.0.42→42%).valueScale: "percent": store whole percents (0–100, e.g.12.5→12.5%).
Optional nullDisplay replaces empty / null / undefined.
You can import { formatDisplayValue } from "table-for-react" for previews or tooling.
Synthetic / action columns (not in API)
Use a key that your rows do not have (e.g. __actions) and render: (row) => … for buttons or links — the cell ignores row[key] when render is set.
- Do not set
sort: trueon pure UI columns unless you also store a comparable value underkey. exportable: falseomits that column from CSV export (otherwise the file would export an empty cells column).
Card view (viewMode="card")
cardLayout—"grid"(default): responsive CSS grid of cards (repeat(auto-fill, minmax(...))inbase.css)."list": flex column of full‑width stacked cards.- Slot styling — override
classNames.cardGrid,cardGrid_list,cardItem,cardFields,card, etc., or useappendClassNamesto layer utilities (e.g. your own Tailwind grid). - Whole card —
cardRenderer={(row, isSelected, toggleSelect) => …}replaces the built-in card body (you control layout and content). - Outer / per-item shell — keep the built-in card body but change how cards are arranged:
renderCardGrid={({ children, className, layout }) => …}— replace the outer wrapper that holds all cards. You usually spreadclassNameonto your root (or drop it and use your own).layoutis"grid"or"list"(same ascardLayout).renderCardItem={({ row, index, rowKey, className, children }) => …}— replace each card’s outer wrapper (default:div+cardItem). Use withrenderCardGridfor a semantic list, e.g.ul/li.
<SmartTable
viewMode="card"
renderCardGrid={({ children, className }) => (
<ul className={className} role="list">
{children}
</ul>
)}
renderCardItem={({ className, children }) => (
<li className={className}>{children}</li>
)}
/* … */
/>Column filters (table view only, enableColumnFilters)
Per-column filtering is driven by column.filter ("select" or "text") or the legacy filterColumns prop (those keys behave like select). enableColumnFilters must be true.
- Predicate + UI apply only when
viewMode !== "card". In card view active filters stay in state but are not applied to rows; the header filter panel is hidden. Closing the panel when switching modes is handled internally (openFilterreset). "select"— distinct primitive values from the current dataset (after search / show-selected narrowing, before column filters); multi-select equality onrow[key]."text"— substring match, case-insensitive, onString(row[key] ?? '').- Always client-side: filters are applied only to
orderedData—whatever is currently in memory. WithenableServerData, that is typically one server page, soselectoptions and matching rows reflect that slice only (search can still hit the server viaserverConfig.searchParamif configured).
Helpers (optional tooling or custom export pipelines):
import { serializeColumnFiltersPayload, applyColumnFiltersToRows } from "table-for-react".
Pagination (enablePagination, pageSize)
Set pageSize from your own state and pass pageSizeOptions (number[]) plus onPageSizeChange={(n) => …} to show a Rows per page <select> beside Prev / Next. Slots: paginationPageSizeWrap, paginationPageSizeLabel, pageSizeSelect, paginationNav.
Search (enableSearch)
- Local rows (
enableServerDataoff): searches the dataset in-memory. - Server mode: set
serverConfig.searchParam(e.g."q") so the trimmed query is sent on each fetch. OmitsearchParamto keep search client-side only over the loaded page. - Backend should read that param (e.g.
?q=...) filter the full list, then paginate and returntotalfor that filtered list.
Other table props (columns, data, enableServerData, serverConfig, …) work as before.
License
MIT
