Repository navigation
DataTable: add bulk actions for selected rows - #8534
rickyzhangca wants to merge 12 commits into
Conversation
🦋 Changeset detectedLatest commit: 8f48df4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
|
🤖 Lint issues have been automatically fixed and committed to this PR. |
There was a problem hiding this comment.
🟡 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}) => { |
| <VisuallyHidden> | ||
| {typeof header.column.header === 'string' ? header.column.header : header.column.header()} | ||
| </VisuallyHidden> |
| useLayoutEffect(() => { | ||
| const element = focusedAction.current | ||
| if (element && !element.isConnected) { |
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>
ad6f3d5 to
8f48df4
Compare


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}),bulkActionsPropsfor group/count localization, andbulkActionsReturnFocusReffor a custom recovery destination.WithBulkActionsstory in the existing DataTable Features section, demonstrating Make internal and Delete selected without extra result messages.Changed
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.Table.Rowmerges its suppliedclassNameto support the shared header layout.clearSelectionremains available to their actions; asynchronous operations should reconcile captured IDs without clearing newer selections.Removed
None from the published API.
Rollout strategy
Additive, opt-in experimental API with a minor
@primer/reactchangeset. Group expansion and cross-page selection are out of scope.Testing & Reviewing
VITEST_FAIL_ON_CONSOLE=true npm test -- --run packages/react/src/DataTableSTORYBOOK_URL=http://localhost:6006 npx playwright test e2e/components/DataTableBulkActions.test.ts --grep @avt --workers=2npm run buildandnpm run type-checknpm ci --quiet.npm run lint:react-compiler --workspace @primer/reactnpm run lint:fix,npm run lint:css,npm run formatandgit diff --checkgit diff --checkalso 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.