Skip to content

DataTable: add bulk actions for selected rows - #8534

Draft
rickyzhangca wants to merge 12 commits into
mainfrom
rickyzhangca-datatable-bulk-actions
Draft

rickyzhangca wants to merge 12 commits into
mainfrom
rickyzhangca-datatable-bulk-actions

Conversation

@rickyzhangca

@rickyzhangca rickyzhangca commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Related to github/primer#6718 and github/primer#6780; does not close either issue.

Builds on row selection merged in #8415 and now targets main. Adds bulk actions within the table header, beside the existing select-all checkbox. Selection replaces visible column labels with “x selected” and consumer-owned actions, using the original header typography and height. There is no separate clear-selection button. Clearing selection restores column labels and sorting controls. Counts and action IDs use the existing effective selection.

Changelog

New

  • Table.BulkActions: selected count and consumer-owned actions.
  • DataTable.renderBulkActions({selectedRows, selectedCount, clearSelection}), bulkActionsProps for group/count localization, and bulkActionsReturnFocusRef for a custom recovery destination.
  • One WithBulkActions story in the existing DataTable Features section, demonstrating Make internal and Delete selected without extra result messages.

Changed

  • Actions occupy a spanning cell within thead, sharing the visual header row with select-all. Column-header names and sort state remain available to assistive technology; hidden sorting buttons are not focusable.
  • The selected count aligns with the original column label; actions have 8px trailing padding. Focused actions scroll into view in narrow tables.
  • Checkbox focus is preserved on selection. Removing a focused action restores focus without overriding a consumer destination or a user's move outside the actions.
  • Table.Row merges its supplied className to support the shared header layout.
  • Consumers own requests, result announcements and dialogs. clearSelection remains available to their actions; asynchronous operations should reconcile captured IDs without clearing newer selections.

Removed

None from the published API.

Rollout strategy

  • No changes needed in github/github-ui
  • Needs changes in github/github-ui
  • Ships with feature flag(s)
  • Not sure
  • None

Additive, opt-in experimental API with a minor @primer/react changeset. Group expansion and cross-page selection are out of scope.

Testing & Reviewing

Command Result
VITEST_FAIL_ON_CONSOLE=true npm test -- --run packages/react/src/DataTable Passed: 203 tests, rerun after rebasing onto main.
STORYBOOK_URL=http://localhost:6006 npx playwright test e2e/components/DataTableBulkActions.test.ts --grep @avt --workers=2 Passed before rebase: 16 tests, including exact header height, typography, left alignment and 8px trailing padding in all three densities, both actions, and keyboard scrolling/focus recovery at 320px with text-spacing overrides.
npm run build and npm run type-check Both passed after rebase and restoring current main dependencies with npm ci --quiet.
npm run lint:react-compiler --workspace @primer/react Passed before rebase.
npm run lint:fix, npm run lint:css, npm run format and git diff --check All passed before rebase; git diff --check also passed afterward.

Only the 12 bulk-actions commits after the old selection head were replayed onto main. The complete binary diff is identical before and after rebase, including review cleanups and Linux snapshots.

The normal-density header measures 38px both before and after selection. The single story uses small action buttons; oversized or wrapping consumer content is not clipped to force a fixed height. Linux light/dark baselines were regenerated successfully by the snapshot workflow, published before rebase in ad6f3d547, and visually inspected.

Review DataTable → Features → With Bulk Actions. This remains a draft pending manual screen-reader verification (VoiceOver/Safari, NVDA and JAWS): confirm body cells retain the correct column headers, the action group is discoverable, counts are announced, and focus recovers after clearing/deletion. Verify actual text enlargement/browser zoom as well. Automated checks do not establish assistive-technology compatibility; the two-row semantic header with a shared visual row still needs that review. A complete renewed accessibility-policy review of the latest incremental changes has not been completed.

@changeset-bot

changeset-bot Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8f48df4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@rickyzhangca rickyzhangca added the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 13, 2026
@github-actions github-actions Bot added the integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Oct 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Action required

👋 Hi, this pull request contains changes to the source code that github/github-ui depends on. If you are GitHub staff, test these changes with github/github-ui using the integration workflow. Check the integration testing docs for step-by-step instructions. Or, apply the integration-tests: skipped manually label to skip these checks.

@primer

primer Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

🤖 Lint issues have been automatically fixed and committed to this PR.

@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 13, 2026 18:20 Inactive
@github-actions github-actions Bot removed the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 13, 2026
@github-actions
github-actions Bot requested a deployment to storybook-preview-8534 October 13, 2026 18:27 Abandoned
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 13, 2026 18:37 Inactive
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 13, 2026 18:59 Inactive
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 13, 2026 22:56 Inactive
@rickyzhangca rickyzhangca added the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 14, 2026
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 14, 2026 00:39 Inactive
@github-actions github-actions Bot removed the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 14, 2026
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 14, 2026 00:50 Inactive
@rickyzhangca rickyzhangca added the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 14, 2026
@github-actions github-actions Bot removed the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 14, 2026
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 14, 2026 01:13 Inactive
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 14, 2026 01:22 Inactive
@rickyzhangca rickyzhangca added the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 14, 2026
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 14, 2026 01:44 Inactive
@github-actions github-actions Bot removed the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Oct 14, 2026
@github-actions
github-actions Bot requested a deployment to storybook-preview-8534 October 14, 2026 01:50 Abandoned
@github-actions
github-actions Bot temporarily deployed to storybook-preview-8534 October 14, 2026 02:01 Inactive
Base automatically changed from agents/implement-row-selection-datatable to main October 14, 2026 16:06
@rickyzhangca
rickyzhangca requested a balanced review from Copilot October 14, 2026 18:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Ref compatibility, keyboard focus behavior, and accessibility CI coverage need correction before approval.

4 open findings
What changed in this PR

Adds opt-in bulk actions to DataTable’s header, building on current-page row selection.

Changes:

  • Adds bulk-action APIs, effective selection counts, and focus recovery.
  • Preserves accessible column labels while displaying consumer-owned actions.
  • Adds documentation, stories, tests, and minor changesets.
File Description
packages/​react/​src/​experimental/​index.ts Exports new public types.
packages/​react/​src/​DataTable/​useTable.ts Adds selection state and actions.
packages/​react/​src/​DataTable/​TableBulkActions.tsx Implements counts and action focus handling.
packages/​react/​src/​DataTable/​TableBulkActions.module.css Styles the shared header layout.
packages/​react/​src/​DataTable/​Table.tsx Adds selection parts and class merging.
packages/​react/​src/​DataTable/​Table.module.css Centers selection controls.
packages/​react/​src/​DataTable/​Table.features.stories.tsx Demonstrates composed selection.
packages/​react/​src/​DataTable/​row.ts Defines the row ID type.
packages/​react/​src/​DataTable/​index.ts Exposes selection and bulk-action parts.
packages/​react/​src/​DataTable/​DataTable.types.test.tsx Covers selection and bulk-action types.
packages/​react/​src/​DataTable/​DataTable.tsx Integrates selection and header actions.
packages/​react/​src/​DataTable/​DataTable.features.stories.tsx Demonstrates selection and bulk operations.
packages/​react/​src/​DataTable/​DataTable.docs.json Documents new APIs and stories.
packages/​react/​src/​DataTable/​DataTable.accessibility.md Describes accessibility responsibilities.
packages/​react/​src/​DataTable/​__tests__/​DataTableSelection.test.tsx Tests selection behavior and hydration.
packages/​react/​src/​DataTable/​__tests__/​DataTableBulkActions.test.tsx Tests actions, announcements, and recovery.
packages/​react/​src/​__tests__/​__snapshots__/​exports.test.ts.snap Records new experimental exports.
e2e/​components/​Table.test.ts Covers composed selection in browsers.
e2e/​components/​DataTableBulkActions.test.ts Covers bulk-action layout and interactions.
e2e/​components/​DataTable.test.ts Expands selection and accessibility coverage.
.changeset/​selectable-data-table-rows.md Records the selection minor release.
.changeset/​data-table-bulk-actions.md Records the bulk-action minor release.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

* Overrides the focus recovery target when a focused bulk action disappears.
* Defaults to select-all, or the table when no selectable rows remain.
*/
bulkActionsReturnFocusRef?: RefObject<HTMLElement>

test.describe('DataTable bulk actions', () => {
for (const theme of themes) {
test(`${theme} @avt`, async ({page}) => {
Comment on lines +272 to +274
<VisuallyHidden>
{typeof header.column.header === 'string' ? header.column.header : header.column.header()}
</VisuallyHidden>
Comment on lines +47 to +49
useLayoutEffect(() => {
const element = focusedAction.current
if (element && !element.isConnected) {
rickyzhangca and others added 12 commits October 14, 2026 15:31
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Clear stale action focus after clicks on non-interactive content, exercise real menu keyboard recovery, and condense the accessibility contract.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the select-all control mounted, retain accessible column labels, and restore sorting controls when selection clears.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the built-in clear action, use the concise selected count, and preserve header dimensions across selection changes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

This branch was successfully deployed

2 active deployments
storybook-preview-8534 — 8f48df42 Deployed Oct 14, 2026 by github-actions[bot]
github-pages — 8f48df42 Deployed Oct 14, 2026 by rickyzhangca via deploy-preview #33702
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants