From 41735f786896075f70d162e0e9b888ae39a319fa Mon Sep 17 00:00:00 2001
From: John Betancur <1385932+jbetancur@users.noreply.github.com>
Date: Sun, 17 May 2026 16:30:01 -0400
Subject: [PATCH 1/3] chore: update issue templates and add contributing
guidelines (#1315)
---
.github/ISSUE_TEMPLATE/bug_report.md | 54 ++++++++++++-----------
.github/ISSUE_TEMPLATE/config.yml | 7 +++
.github/ISSUE_TEMPLATE/feature_request.md | 26 +++++------
.github/PULL_REQUEST_TEMPLATE.md | 34 ++++++++++++++
.github/stale.yml | 9 ++--
.github/workflows/ci.yml | 32 ++++++++++++++
CONTRIBUTING.md | 46 +++++++++++++++++++
7 files changed, 166 insertions(+), 42 deletions(-)
create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
create mode 100644 .github/workflows/ci.yml
create mode 100644 CONTRIBUTING.md
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index ce999ab7..b911be50 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,45 +1,49 @@
---
name: Bug report
about: Create a report to help us improve
-title: "[DESCRIPTION]"
-labels: ''
+title: "[BUG]: "
+labels: 'bug'
assignees: ''
---
-## Issue Check list
-- [ ] Agree to the [Code of Conduct](https://github.com/jbetancur/react-data-table-component/blob/master/CODE-OF-CONDUCT.md)
-- [ ] Read the README
-- [ ] You are using React 16.8.0+
-- [ ] You installed `styled-components`
-- [ ] Include relevant code or preferably a [code sandbox](https://codesandbox.io/embed/react-data-table-sandbox-ccyuu
-)
+## Checklist
+
+- [ ] I agree to the [Code of Conduct](https://github.com/jbetancur/react-data-table-component/blob/master/CODE-OF-CONDUCT.md)
+- [ ] I searched [existing issues](https://github.com/jbetancur/react-data-table-component/issues?q=is%3Aissue) and this is not a duplicate
+- [ ] I read the [documentation](https://reactdatatable.com)
+- [ ] I am using React 18+
+- [ ] I can reproduce this with a minimal example (sandbox link below)
## Describe the bug
+
A clear and concise description of what the bug is.
## To Reproduce
+
Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
+
+1.
+2.
+3.
## Expected behavior
-A clear and concise description of what you expected to happen.
-## Code Sandbox, Screenshots, or Relevant Code
-Please include a codesandbox to help **expedite** troublshooting.
+What you expected to happen.
+
+## Actual behavior
+
+What actually happens.
+
+## Minimal reproduction
-https://codesandbox.io/embed/react-data-table-sandbox-ccyuu
+**A minimal reproduction is required — issues without one may be closed.**
-Otherwise, add screenshots and/or complete sample code to help explain your problem.
+
-## Versions (please complete the following information)
- - React (RDT requires 16.8.0+)
- - Styled Components
- - OS: [e.g. iOS]
- - Browser [e.g. chrome, safari, firefox]
+## Versions
-## Additional context
-Add any other context about the problem here.
+- react-data-table-component:
+- React:
+- Browser:
+- OS:
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 3ba13e0c..fabeab1c 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1 +1,8 @@
blank_issues_enabled: false
+contact_links:
+ - name: Documentation & Recipes
+ url: https://reactdatatable.com
+ about: Check the docs and recipes — most questions are already answered here.
+ - name: GitHub Discussions
+ url: https://github.com/jbetancur/react-data-table-component/discussions
+ about: Ask usage questions, share ideas, or get help from the community.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index e2ebfab9..74916eeb 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,32 +1,32 @@
---
name: Feature request
about: Suggest an idea for this project
-title: "[FEATURE]: [SHORT DESCRIPTION]"
-labels: ''
+title: "[FEATURE]: "
+labels: 'enhancement'
assignees: ''
---
-## Feature Check list
+## Checklist
-- [ ] Agree to the [Code of Conduct](https://github.com/jbetancur/react-data-table-component/blob/master/CODE-OF-CONDUCT.md)
-- [ ] Read the README to ensure the feature is not already present
-- [ ] You read [Creating Issues, Features and Pull Requests](https://github.com/jbetancur/react-data-table-component/issues/387)
-- [ ] Considered the value versus complexity for all users of the library as well as library maintenance
-- [ ] Considered if this can be a storybook or documentation example
+- [ ] I agree to the [Code of Conduct](https://github.com/jbetancur/react-data-table-component/blob/master/CODE-OF-CONDUCT.md)
+- [ ] I searched [existing issues](https://github.com/jbetancur/react-data-table-component/issues?q=is%3Aissue) and this has not been requested before
+- [ ] I read the [documentation](https://reactdatatable.com) and this feature does not already exist
+- [ ] I considered whether this could be solved with a documentation example or recipe instead
+- [ ] I considered the maintenance burden and value for all library users
-## Is your feature request related to a problem? Please describe
+## Is your feature request related to a problem?
-A clear and concise description of what the feature is.
+A clear and concise description of what the problem is.
## Describe the solution you'd like
A clear and concise description of what you want to happen.
-## Describe alternatives you've considered
+## Alternatives considered
-A clear and concise description of any alternative solutions or features you've considered.
+Any alternative solutions or workarounds you've considered.
## Additional context
-Add any other context or screenshots about the feature request here.
+Screenshots, examples, or any other context about the feature request.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..63302f0a
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,34 @@
+
+
+## Summary
+
+
+
+Fixes #
+
+## Type of change
+
+- [ ] Bug fix
+- [ ] New feature
+- [ ] Breaking change
+- [ ] Documentation / example update
+- [ ] Refactor / internal cleanup
+
+## Checklist
+
+- [ ] I read [CONTRIBUTING.md](https://github.com/jbetancur/react-data-table-component/blob/master/CONTRIBUTING.md)
+- [ ] I agree to the [Code of Conduct](https://github.com/jbetancur/react-data-table-component/blob/master/CODE-OF-CONDUCT.md)
+- [ ] Tests pass (`npm test`)
+- [ ] No TypeScript errors (`npm run typecheck`)
+- [ ] I have updated docs or examples if needed
+
+## Breaking changes
+
+
+
+## How to test
+
+
diff --git a/.github/stale.yml b/.github/stale.yml
index b0ad5155..ac2c9ea0 100644
--- a/.github/stale.yml
+++ b/.github/stale.yml
@@ -8,12 +8,13 @@ exemptLabels:
- security
- enhancement
- feature
+ - bug
# Label to use when marking an issue as stale
-staleLabel: wontfix
+staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
- This issue has been automatically marked as stale because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
+ This issue has been automatically marked as stale due to inactivity.
+ It will be closed in 7 days if there is no further activity.
+ If this is still relevant, please leave a comment or update the issue.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..c7b1e562
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,32 @@
+name: CI
+
+on:
+ pull_request:
+ branches: [master]
+
+jobs:
+ ci:
+ name: Lint, typecheck, test, build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Lint
+ run: npm run lint
+
+ - name: Typecheck
+ run: npm run typecheck
+
+ - name: Test
+ run: npm test
+
+ - name: Build
+ run: npm run build
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..0d0def84
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,46 @@
+# Contributing
+
+Thanks for your interest in contributing. Please read this before opening a PR.
+
+## What gets merged
+
+This is a focused, stable library. The bar for new features is high — complexity must be justified by broad utility. Most things that feel like features are better solved with a documentation example.
+
+PRs that get merged quickly:
+
+- Bug fixes with a clear reproduction
+- TypeScript or accessibility improvements
+- Documentation or example improvements
+
+PRs that get closed:
+
+- No linked issue or description
+- Adds niche features better handled in userland
+- Breaks existing API without strong justification
+- Fails CI (lint, typecheck, tests, build)
+
+## Before you open a PR
+
+1. **Open an issue first** for anything non-trivial. Alignment before code saves everyone time.
+2. **Keep the scope small.** One concern per PR.
+3. **Check CI passes** locally before pushing: `npm run lint && npm run typecheck && npm test && npm run build`
+
+## Development setup
+
+```bash
+npm install
+npm test # run tests
+npm run typecheck # check types
+npm run lint # check lint
+npm run build # build the library
+```
+
+## Code style
+
+- TypeScript, no `any`
+- Prettier + ESLint enforced — run `npm run format` if needed
+- No new dependencies without discussion
+
+## Questions
+
+Usage questions belong in [Discussions](https://github.com/jbetancur/react-data-table-component/discussions) or the [docs](https://reactdatatable.com), not issues or PRs.
From 52125148ebb4dd48869bcd9a5549647dfd718da8 Mon Sep 17 00:00:00 2001
From: John Betancur <1385932+jbetancur@users.noreply.github.com>
Date: Sun, 17 May 2026 16:39:01 -0400
Subject: [PATCH 2/3] feat: add controlled paginationPage prop and update API
documentation (#1316)
---
apps/docs/src/pages/docs/api.md | 3 +-
apps/docs/src/pages/docs/changelog.astro | 14 +++++-
src/__tests__/DataTable.test.tsx | 57 ++++++++++++++++++++++++
src/components/DataTable.tsx | 2 +
src/hooks/useTableState.ts | 9 ++++
src/types.ts | 1 +
6 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/apps/docs/src/pages/docs/api.md b/apps/docs/src/pages/docs/api.md
index 5d511143..fcef6f95 100644
--- a/apps/docs/src/pages/docs/api.md
+++ b/apps/docs/src/pages/docs/api.md
@@ -86,7 +86,8 @@ Complete reference for every prop, type, and export in `react-data-table-compone
| `paginationPerPage` | `number` | `10` | Rows shown per page. |
| `paginationRowsPerPageOptions` | `number[]` | `[10,15,20,25,30]` | Options in the rows-per-page dropdown. |
| `paginationDefaultPage` | `number` | `1` | Initial active page. |
-| `paginationResetDefaultPage` | `boolean` | `false` | Toggle to reset to page 1 (e.g. after a filter change). |
+| `paginationPage` | `number` | - | Controlled active page. When provided, the table navigates to this page whenever the value changes. Use together with `onChangePage` to keep them in sync. |
+| `paginationResetDefaultPage` | `boolean` | `false` | Toggle to reset to page 1 (e.g. after a filter change). Prefer `paginationPage` for new code. |
| `paginationTotalRows` | `number` | - | Total row count for server-side pagination. |
| `paginationServer` | `boolean` | `false` | Delegate page changes to `onChangePage` / `onChangeRowsPerPage`. |
| `paginationServerOptions` | `PaginationServerOptions` | - | Selection-persistence options for server-side mode. |
diff --git a/apps/docs/src/pages/docs/changelog.astro b/apps/docs/src/pages/docs/changelog.astro
index c3c6c238..2d14af75 100644
--- a/apps/docs/src/pages/docs/changelog.astro
+++ b/apps/docs/src/pages/docs/changelog.astro
@@ -11,7 +11,19 @@ import CodeBlock from '../../components/CodeBlock.astro';
repository on GitHub.
-
8.1.0 (current)
+
8.2.0 (unreleased)
+
+
New features
+
+
+ paginationPage — controlled active-page prop. Set it to navigate the table
+ programmatically (e.g. reset to page 1 after a filter change). Use together with
+ onChangePage to keep them in sync.
+ → API reference
+
{selectedRows.length > 0 && (
-
+
{selectedRows.length} selected: {selectedRows.map(r => r.name).join(', ')}
)}
diff --git a/apps/docs/src/layouts/DocsLayout.astro b/apps/docs/src/layouts/DocsLayout.astro
index d19f8fe7..b7a0d3da 100644
--- a/apps/docs/src/layouts/DocsLayout.astro
+++ b/apps/docs/src/layouts/DocsLayout.astro
@@ -50,6 +50,7 @@ const nav = [
{ label: 'Conditional Styles', href: '/docs/conditional-styles' },
{ label: 'Fixed Header', href: '/docs/fixed-header' },
{ label: 'Pagination', href: '/docs/pagination' },
+ { label: 'Footer', href: '/docs/footer' },
{ label: 'Loading State', href: '/docs/loading' },
],
},
diff --git a/apps/docs/src/pages/docs/api.md b/apps/docs/src/pages/docs/api.md
index fcef6f95..1e852b8a 100644
--- a/apps/docs/src/pages/docs/api.md
+++ b/apps/docs/src/pages/docs/api.md
@@ -97,6 +97,15 @@ Complete reference for every prop, type, and export in `react-data-table-compone
| `onChangePage` | `(page, totalRows) => void` | - | Called when the active page changes. |
| `onChangeRowsPerPage` | `(rowsPerPage, page) => void` | - | Called when rows-per-page selection changes. |
+### Footer
+
+| Prop | Type | Default | Description |
+|---|---|---|---|
+| `footerComponent` | `ComponentType>` | - | Replace the footer row with a custom component. Receives `{ rows, columns }`. Takes precedence over column-level `footer` fields. |
+| `showFooter` | `boolean` | - | Force the footer row on or off. By default the footer renders when `footerComponent` is set or any visible column declares a `footer`. Set to `false` to suppress, `true` to render an empty footer row. |
+
+Column-level footers live on each [`TableColumn`](#tablecolumnt) as the `footer` field. See [Footer](/docs/footer) for the full walkthrough.
+
### Row selection
| Prop | Type | Default | Description |
@@ -219,6 +228,7 @@ const columns: TableColumn[] = [
| `reorder` | `boolean` | Allow drag-to-reorder for this column (requires `reorder` on at least two columns). |
| `style` | `CSSProperties` | Inline styles applied to every cell in this column. |
| `conditionalCellStyles` | `ConditionalStyles[]` | Per-cell conditional styles. |
+| `footer` | `ReactNode \| (rows: T[]) => ReactNode` | Footer cell for this column. Static node or a function receiving the filtered+sorted rows (typically used to render aggregates like sums or averages). When any visible column has a `footer`, a footer row renders below the body. See [Footer](/docs/footer). |
### Inline editing
@@ -361,6 +371,8 @@ const customStyles: TableStyles = {
| `expanderCell` | - | Cell containing the expand/collapse button. |
| `expanderButton` | - | The expand/collapse button itself. |
| `pagination` | `pageButtonsStyle` | Pagination bar and page buttons. |
+| `footer` | - | The footer row container. |
+| `footerCells` | - | Individual footer cells. |
| `noData` | - | Empty-state container. |
| `progress` | - | Loading indicator container. |
diff --git a/apps/docs/src/pages/docs/changelog.astro b/apps/docs/src/pages/docs/changelog.astro
index 2d14af75..a7dd5109 100644
--- a/apps/docs/src/pages/docs/changelog.astro
+++ b/apps/docs/src/pages/docs/changelog.astro
@@ -21,6 +21,28 @@ import CodeBlock from '../../components/CodeBlock.astro';
onChangePage to keep them in sync.
→ API reference
+
+ Built-in footer row for totals, averages, and other summary cells.
+ Declare per-column with the new footer field
+ (ReactNode or (rows) => ReactNode) or replace the whole
+ row with the footerComponent prop. Footer cells respect column widths,
+ alignment, and pinning automatically.
+ → Footer docs
+
+
+ Pagination button aria-labels — "First Page", "Previous Page", "Next Page",
+ and "Last Page" are now configurable via paginationComponentOptions, enabling
+ proper i18n for screen readers.
+
+
+
+
Bug fixes
+
+
+ Fixed column reordering bypassing reorder={false} when a cell's text
+ was selected via double-click and then dragged. The cell now correctly gates all drag
+ handlers on column.reorder.
+
8.1.0
@@ -46,7 +68,8 @@ import CodeBlock from '../../components/CodeBlock.astro';
New headless export hook useTableExport: build CSV/JSON, trigger a
- download, or copy to clipboard.
+ download, or copy to clipboard. Import directly from the package:
+ import { useTableExport } from 'react-data-table-component'.
→ Export
+ A footer row renders below the body and above the pagination controls. Use it for totals,
+ averages, counts, or any other summary that should always be visible alongside the data.
+
+
+
+ There are two ways to declare a footer:
+
+
+
+
+ Column-level footer — the 80% case. Add a footer field
+ to any TableColumn. The footer row appears automatically when at least one
+ visible column has one.
+
+
+ footerComponent prop — escape hatch. Replace the entire footer
+ row with a custom component when you need multi-row summaries, custom layouts, or aggregates
+ that span columns.
+
+
+
+
Column-level footers
+
+
+ Pass footer as either a static ReactNode or a function that receives
+ the filtered+sorted rows and returns a node. Use the function form to compute aggregates —
+ it sees exactly the rows the user sees in the body, so totals update automatically when you
+ sort or filter.
+
+ Each footer cell inherits its column's right, center,
+ width, minWidth, and maxWidth — so totals line up
+ under their column automatically, including after a resize or sort.
+
+
+
+ Server-side pagination: the rows argument to a footer function
+ contains only the rows currently in the table (the current page). If you need true cross-page
+ totals, use footerComponent and supply server-computed aggregates yourself.
+
+
+
Custom footer component
+
+
+ Pass footerComponent to replace the footer row entirely. The component receives
+ {`{ rows, columns }`} and can render whatever it likes — multi-stat summaries,
+ action buttons, contextual copy, anything.
+
+ When footerComponent is set it takes precedence over any column-level
+ footer fields.
+
+
+
Controlling footer visibility
+
+
+ The showFooter prop overrides auto-detection:
+
+
+
+
showFooter — force the footer row on even if no column defines a footer.
+
showFooter={`{false}`} — suppress the footer entirely, overriding column footers and footerComponent. Useful for toggling the summary on and off.
+
Omitted (default) — auto: render when any visible column has footer or footerComponent is provided.
+
+
+
+ The footer is also automatically hidden during progressPending.
+
+
+
Styling
+
+
+ Use customStyles to override footer appearance:
+
+
+ `} />
+
+
+ All built-in themes (including their dark modes) set a background.footer value
+ that gives the footer a distinct surface color matching the header. When building a custom
+ theme with createTheme, set background.footer to control it:
+
+
+
+
+
+ The CSS variable --rdt-color-footer-bg is emitted automatically when
+ background.footer is set. You can also set it directly in a raw CSS-variable
+ theme object. It falls back to --rdt-color-header-bg, then
+ --rdt-color-bg.
+
+
+
Pinned columns
+
+
+ Footer cells in pinned columns stick to the table edge exactly like their body cells — no
+ extra config required. Pinning offsets are computed from the same source as the rest of the
+ table, so they stay aligned after resizing.
+
+
+
Tips
+
+
+
+ Match the footer's display format to the column's format function. If salaries
+ render as $45,000, format the total the same way.
+
+
+ Use a static label (footer: 'Total') on the leftmost column and aggregate
+ functions on numeric columns.
+
+
+ For multi-row footers, group subtotals, or any layout that doesn't map 1:1 to columns,
+ reach for footerComponent — it renders inside a role="rowgroup"
+ container for accessibility and has no constraints on its internal structure.
+
- Render a toolbar above the table that appears when one or more rows are selected. Use the
- imperative ref to clear the selection after the action completes.
+ v8 removed the built-in contextMessage and contextActions props.
+ The recommended replacement is a toolbar rendered outside the table, driven by
+ onSelectedRowsChange. This gives you full control over layout, styling,
+ and what actions appear.
+
+
+
+ Show the toolbar only when rows are selected, display a count and names, and use the
+ imperative ref to clear selection after the action completes.
);
}`} />
@@ -225,8 +252,9 @@ function OrderDetail({ data }: ExpanderComponentProps) {
Sticky footer with totals
- There's no built-in footer slot. The simplest pattern is to render a totals row outside
- the table that aligns to the same column layout:
+ Use the built-in footer — add a footer field on any
+ column and the table renders an aligned totals row automatically. If you'd rather render
+ your own summary outside the table, the pattern below still works:
+
Custom selection toolbar
+
+ v8 removed the built-in contextMessage and contextActions props.
+ Use onSelectedRowsChange to drive your own toolbar rendered outside the table —
+ you get full control over layout, copy, and actions. See the
+ bulk-action toolbar recipe for a complete example.
+