Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ github: [jbetancur]
# patreon: # Replace with a single Patreon username
open_collective: react-data-table-component
# ko_fi: # Replace with a single Ko-fi username
tidelift: npm/react-data-table-component
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

A summary of notable changes per release. For the full commit history see the [repository on GitHub](https://github.com/jbetancur/react-data-table-component/commits/master).

## 8.6.1

### Bug fixes

- A custom `progressComponent` could not be shown on the initial load — the skeleton rows always won. New `progressSkeleton` prop (default `true`) lets you set it to `false` to show your `progressComponent` on initial load instead. → [Loading state](/docs/loading)

---

## 8.6.0

### New features
Expand Down
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,28 @@ The documentation contains information about installation, usage and contributio

# Supporting React Data Table Component

React Data Table Component has been actively maintained since 2018 and is downloaded ~215k times a week. If your team ships products with it, your support keeps it maintained, bug-free, and moving forward.
React Data Table Component has been actively maintained since 2018 and is downloaded ![weekly downloads](https://img.shields.io/npm/dw/react-data-table-component.svg?label=%20&color=blue&style=flat-square) times a week. If your team ships products with it, your support keeps it maintained, bug-free, and moving forward.

## Sponsor the project

Sponsoring puts your company logo in front of ~215k developers a week: in the README, the docs site, and every release. It's the right move if your team depends on this library and you want it to keep improving.
Sponsoring puts your company logo in front of the ![weekly downloads](https://img.shields.io/npm/dw/react-data-table-component.svg?label=%20&color=blue&style=flat-square) developers who use it every week: in the README, the docs site, and every release. It's the right move if your team depends on this library and you want it to keep improving.

| Tier | Price/month | Perk |
| --- | --- | --- |
| ☕ Supporter | $5 | Your name in the README supporters list |
| 🎗 Backer | $20 | Name + link in README + listed in the Backers section on reactdatatable.com |
| 🥉 Bronze | $100 | Priority issue triage + small logo in README + docs site footer |
| 🥈 Silver | $200 | Priority issue triage + medium logo in README + docs site sidebar |
| 🥇 Gold | $500 | Priority issue triage + direct maintainer line + large logo in README + hero spot on reactdatatable.com. Limited to 3. |
| 🥉 Bronze | $100 | Visibility: small logo in README + docs site footer, and sponsor credit in every release's notes |
| 🥈 Silver | $200 | Everything in Bronze + medium logo in the docs sidebar + priority issue queue: sponsor issues go to the front of the backlog, first response within 2 business days |
| 🥇 Gold | $500 | Everything in Silver + hero logo on reactdatatable.com + top README placement + written support commitments: 12-month patch window for the previous major, security advisories before public disclosure, one compliance questionnaire per year, direct email channel (async, business hours). Limited to 3. |

These are honest, written commitments from a solo maintainer: async and business hours. No fake 24/7 SLA.

[![Sponsor on GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-ea4aaa?logo=github)](https://github.com/sponsors/jbetancur)
[![Sponsor on OpenCollective](https://img.shields.io/badge/Sponsor-OpenCollective-blue?logo=opencollective)](https://opencollective.com/react-data-table-component)

## Enterprise support

Available as part of the Tidelift Subscription.

The maintainer of react-data-table-component and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-react-data-table-component?utm_source=npm-react-data-table-component&utm_medium=referral&utm_campaign=readme)

<!-- TODO: replace the Tidelift link above with the exact referral URL from the dashboard's "Promote the Tidelift Subscription" marketing task. -->
Need commercial support, an SLA, or help with a major version upgrade? I offer direct consulting and priority support arrangements for teams that depend on react-data-table-component in production. Reach out via the [support page](https://reactdatatable.com/support).

## Need help?

Expand Down
3 changes: 2 additions & 1 deletion apps/docs/public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const columns = [
- [Column Reordering](https://reactdatatable.com/docs/column-reorder): drag to reorder, mouse or touch (press-and-hold on touch)
- [Column Resizing](https://reactdatatable.com/docs/resizable): drag column edges by mouse or touch, persist widths
- [Column Pinning](https://reactdatatable.com/docs/column-pinning): pin columns left or right
- [Column Separators](https://reactdatatable.com/docs/column-separators): vertical divider lines between header and body columns
- [Column Filtering](https://reactdatatable.com/docs/filtering): per-column text, number, and select filters
- [Sorting](https://reactdatatable.com/docs/sorting): client-side and server-side sorting

Expand Down Expand Up @@ -87,6 +88,6 @@ const columns = [
## Optional

- [Changelog](https://reactdatatable.com/docs/changelog): release history
- [Support & Sponsorship](https://reactdatatable.com/support): sponsor tiers, enterprise support via Tidelift
- [Support & Sponsorship](https://reactdatatable.com/support): sponsor tiers, direct consulting and enterprise support
- [GitHub repository](https://github.com/jbetancur/react-data-table-component)
- [npm package](https://www.npmjs.com/package/react-data-table-component)
85 changes: 85 additions & 0 deletions apps/docs/src/components/PropsTable.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
import DocsTable from './DocsTable.astro';
import { dataTableProps, propGroupOrder, type PropDef, type PropFeature, type PropGroup } from '../data/props';

type Column = 'prop' | 'type' | 'default' | 'description';

interface Props {
// Filter by feature tag (feature pages) …
feature?: PropFeature;
// … or render whole api.md-style groups (the API reference).
group?: PropGroup;
groups?: PropGroup[];
// Restrict/order the rows explicitly by prop name (overrides feature/group).
only?: string[];
// Which columns to render. Default omits the Default column on feature pages.
columns?: Column[];
// Prefer the shorter `brief` copy where available. Defaults to true unless a
// group is given (the API reference wants the canonical description).
brief?: boolean;
// Header label for the first column.
propHeader?: string;
}

const {
feature,
group,
groups,
only,
columns,
brief = !group && !groups,
propHeader = 'Prop',
} = Astro.props as Props;

const byName = new Map(dataTableProps.map(p => [p.name, p] as const));

let rows: PropDef[];
if (only) {
rows = only.map(name => {
const p = byName.get(name);
if (!p) throw new Error(`PropsTable: unknown prop "${name}" in \`only\``);
return p;
});
} else if (feature) {
rows = dataTableProps.filter(p => p.features.includes(feature));
} else {
const wanted = groups ?? (group ? [group] : propGroupOrder);
rows = dataTableProps.filter(p => wanted.includes(p.group));
}

if (rows.length === 0) {
throw new Error(`PropsTable: no props matched (feature=${feature}, group=${group}).`);
}

// Row events have no defaults in the source; drop the Default column when none
// of the selected rows define one, unless the caller pins the columns.
const anyDefault = rows.some(p => p.default != null && p.default !== '');
const cols: Column[] = columns ?? (anyDefault ? ['prop', 'type', 'default', 'description'] : ['prop', 'type', 'description']);

const headerFor: Record<Column, string> = {
prop: propHeader,
type: 'Type',
default: 'Default',
description: 'Description',
};
const headers = cols.map(col => headerFor[col]);

const cellFor = (p: PropDef, col: Column): string => {
switch (col) {
case 'prop': {
const label = `<code>${p.name}</code>`;
return p.deprecated ? `<s>${label}</s>` : label;
}
case 'type':
return p.type;
case 'default':
return p.default ?? '-';
case 'description':
return (brief && p.brief) || p.description;
}
};

const tableRows = rows.map(p => cols.map(col => cellFor(p, col)));
---

<DocsTable headers={headers} rows={tableRows} />
1 change: 0 additions & 1 deletion apps/docs/src/components/demos/FooterBasicDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export default function FooterBasicDemo() {
columns={columns}
data={data}
highlightOnHover
dense
/>
</div>
);
Expand Down
31 changes: 20 additions & 11 deletions apps/docs/src/components/demos/InlineEditingDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ interface Employee {
department: Department;
status: Status;
salary: number;
remote: boolean;
}

const initialData: Employee[] = [
{ id: 1, name: 'Aria Chen', department: 'Engineering', status: 'Active', salary: 155000 },
{ id: 2, name: 'Marcus Webb', department: 'Product', status: 'Active', salary: 132000 },
{ id: 3, name: 'Priya Kapoor', department: 'Design', status: 'On Leave', salary: 118000 },
{ id: 4, name: 'Jordan Ellis', department: 'Analytics', status: 'Active', salary: 143000 },
{ id: 5, name: 'Sam Rivera', department: 'Engineering', status: 'Terminated', salary: 128000 },
{ id: 1, name: 'Aria Chen', department: 'Engineering', status: 'Active', salary: 155000, remote: true },
{ id: 2, name: 'Marcus Webb', department: 'Product', status: 'Active', salary: 132000, remote: false },
{ id: 3, name: 'Priya Kapoor', department: 'Design', status: 'On Leave', salary: 118000, remote: true },
{ id: 4, name: 'Jordan Ellis', department: 'Analytics', status: 'Active', salary: 143000, remote: false },
{ id: 5, name: 'Sam Rivera', department: 'Engineering', status: 'Terminated', salary: 128000, remote: false },
];

const statusColors: Record<Status, string> = {
Expand All @@ -33,9 +34,8 @@ export default function InlineEditingDemo() {

const handleCellEdit = (row: Employee, value: string, column: TableColumn<Employee>) => {
const field = column.id as keyof Employee;
setData(prev =>
prev.map(r => (r.id === row.id ? { ...r, [field]: field === 'salary' ? Number(value) || r.salary : value } : r)),
);
const parsed = field === 'salary' ? Number(value) || row.salary : field === 'remote' ? value === 'true' : value;
setData(prev => prev.map(r => (r.id === row.id ? { ...r, [field]: parsed } : r)));
setLastEdit(`Updated ${row.name} → ${String(column.name)}: "${value}"`);
};

Expand Down Expand Up @@ -101,15 +101,24 @@ export default function InlineEditingDemo() {
editable: true,
onCellEdit: handleCellEdit,
},
{
id: 'remote',
name: 'Remote',
selector: r => r.remote,
format: r => (r.remote ? 'Yes' : 'No'),
center: true,
editor: { type: 'checkbox' },
onCellEdit: handleCellEdit,
},
];

return (
<div className="space-y-2">
<p className="text-xs text-gray-400">
Click any cell to edit. <strong>Name</strong> and <strong>Salary</strong> are text inputs;{' '}
<strong>Department</strong> and <strong>Status</strong> are dropdowns. <kbd>Enter</kbd> commits, <kbd>Esc</kbd>{' '}
cancels. Keyboard navigation is enabled too: click or Tab into the table, move between cells and headers with
the arrow keys, and press <kbd>Enter</kbd> to edit or sort.
<strong>Department</strong> and <strong>Status</strong> are dropdowns; <strong>Remote</strong> is a checkbox.{' '}
<kbd>Enter</kbd> commits, <kbd>Esc</kbd> cancels. Keyboard navigation is enabled too: click or Tab into the
table, move between cells and headers with the arrow keys, and press <kbd>Enter</kbd> to edit or sort.
</p>
<DataTable columns={columns} data={data} highlightOnHover cellNavigation />
{lastEdit && <div className="text-xs text-emerald-600 font-mono">{lastEdit}</div>}
Expand Down
35 changes: 34 additions & 1 deletion apps/docs/src/components/demos/LoadingDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,19 @@ function delay(ms: number) {

type Mode = 'initial' | 'refetch' | 'idle';

const customLoader = (
<div className="flex flex-col items-center gap-2 text-brand-600">
<div className="h-6 w-6 rounded-full border-2 border-brand-200 border-t-brand-600 animate-spin" />
<span className="text-xs font-medium">Fetching employees…</span>
</div>
);

export default function LoadingDemo() {
const [mode, setMode] = useState<Mode>('idle');
const [data, setData] = useState<Row[]>(ROWS);
const [pending, setPending] = useState(false);
const [useCustom, setUseCustom] = useState(false);
const [skeleton, setSkeleton] = useState(true);

async function simulateInitial() {
setData([]);
Expand Down Expand Up @@ -67,16 +76,40 @@ export default function LoadingDemo() {
<button className={btnSecondary} disabled={pending} onClick={simulateRefetch}>
Simulate re-fetch
</button>
<label className="flex items-center gap-1.5 text-xs text-gray-500 cursor-pointer select-none">
<input
type="checkbox"
checked={useCustom}
disabled={pending}
onChange={e => setUseCustom(e.target.checked)}
/>
Use custom loader
</label>
<label className="flex items-center gap-1.5 text-xs text-gray-500 cursor-pointer select-none">
<input
type="checkbox"
checked={skeleton}
disabled={pending}
onChange={e => setSkeleton(e.target.checked)}
/>
Skeleton on initial load
</label>
{mode !== 'idle' && (
<span className="text-xs text-gray-400 italic">
{mode === 'initial' ? 'Loading with no existing data — skeleton rows shown' : 'Re-fetching — existing rows dimmed, spinner overlaid'}
{mode === 'initial'
? skeleton
? 'Loading with no existing data — skeleton rows shown'
: 'Loading with no existing data — progress component shown'
: 'Re-fetching — existing rows dimmed, indicator overlaid'}
</span>
)}
</div>
<DataTable
columns={columns}
data={data}
progressPending={pending}
progressComponent={useCustom ? customLoader : undefined}
progressSkeleton={skeleton}
highlightOnHover
striped
/>
Expand Down
9 changes: 9 additions & 0 deletions apps/docs/src/data/backers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Single source of truth for Backer-tier ($20/mo) sponsors and above.
// Rendered on both /support and the homepage sponsors section.
// Add names here as they sign on — keep README.md's "## Backers" list in sync by hand.
export interface Backer {
name: string;
url?: string;
}

export const backers: Backer[] = [{ name: 'Rich Tillman', url: 'https://opencollective.com/rich-tillman' }];
Loading
Loading