Skip to content

feat(Table): add indeterminate checkbox state support for select-all header#12411

Open
rhamilto wants to merge 1 commit intopatternfly:mainfrom
rhamilto:feat/table-indeterminate-checkbox
Open

feat(Table): add indeterminate checkbox state support for select-all header#12411
rhamilto wants to merge 1 commit intopatternfly:mainfrom
rhamilto:feat/table-indeterminate-checkbox

Conversation

@rhamilto
Copy link
Copy Markdown
Member

@rhamilto rhamilto commented May 5, 2026

Summary

Adds support for indeterminate state to the Table component's select-all checkbox in the header, following PatternFly's bulk selection design guidelines.

The select-all checkbox now properly supports three states:

  • Unchecked - no items selected
  • Indeterminate (dash/minus icon) - some items selected
  • Checked - all items selected

Changes

  • Added isIndeterminate?: boolean property to ThSelectType interface
  • Updated selectable decorator to pass indeterminate state to SelectColumn
  • Updated SelectColumn component to set indeterminate property via ref using useEffect
  • Updated Th component to pass isIndeterminate to the selectable decorator
  • Updated TableSelectable example to demonstrate indeterminate state
  • Added new TableSelectableIndeterminate example showcasing the feature

Technical implementation

The indeterminate state on HTML checkboxes must be set via the DOM property (not as a React prop), so this is handled using a ref and useEffect in the SelectColumn component.

useEffect(() => {
  if (inputRef.current && selectVariant === RowSelectVariant.checkbox) {
    inputRef.current.indeterminate = !!isIndeterminate;
  }
}, [inputRef, isIndeterminate, selectVariant]);

Usage example

<Th
  select={{
    onSelect: (_event, isSelecting) => selectAllRepos(isSelecting),
    isSelected: areAllReposSelected,
    isIndeterminate: areSomeReposSelected  // NEW: shows dash when some selected
  }}
  aria-label="Row select"
/>

Related issues

Test plan

  • Build passes without TypeScript errors
  • Visual testing of TableSelectable example shows indeterminate state when some rows selected
  • Accessibility: Screen readers properly announce the checkbox state
  • Checkbox toggles correctly between all three states

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Table selection supports an indeterminate header checkbox (partial selection).
    • Row checkboxes remain normal; header shows indeterminate when some selectable rows are chosen.
    • Multi-row range selection via shift+click and per-row disablement retained.
  • Documentation

    • Added example and docs demonstrating indeterminate header, per-row disabling, and range selection.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Walkthrough

Adds an optional isIndeterminate flag through table selection types and wiring, and updates SelectColumn to render the header select checkbox in an indeterminate state (checkbox variant) by passing appropriate props to the Checkbox. Example, docs, and decorator wiring are updated to demonstrate and pass the state.

Changes

Indeterminate Checkbox State for Table Headers

Layer / File(s) Summary
Type System
packages/react-table/src/components/Table/base/types.tsx, packages/react-table/src/components/Table/TableTypes.tsx
Add optional isIndeterminate?: boolean to ThSelectType and IColumn.extraParams.
Component Props
packages/react-table/src/components/Table/SelectColumn.tsx
SelectColumnProps gains isIndeterminate?: boolean.
Core Component Rendering
packages/react-table/src/components/Table/SelectColumn.tsx
When selectVariant === RowSelectVariant.checkbox, builds checkboxProps and conditionally sets isChecked: null when isIndeterminate is truthy (PatternFly indeterminate signal); renders <Checkbox {...checkboxProps} /> for checkbox variant.
Decorator / Wiring
packages/react-table/src/components/Table/utils/decorators/selectable.tsx, packages/react-table/src/components/Table/Th.tsx
Th forwards select?.isIndeterminate into selectable(...).extraParams; selectable reads isIndeterminate and passes it to header SelectColumn only when rowId === -1.
Examples / Docs
packages/react-table/src/components/Table/examples/TableSelectable.tsx, packages/react-table/src/components/Table/examples/TableSelectableIndeterminate.tsx, packages/react-table/src/components/Table/examples/Table.md
TableSelectable computes areSomeReposSelected and passes it as header isIndeterminate; adds new TableSelectableIndeterminate example demonstrating partial selection, per-row disable and shift+click range selection; docs include a "Selectable with indeterminate state" section referencing the example.

Sequence Diagram

sequenceDiagram
    participant App as App State
    participant Th as Th Component
    participant Selectable as Selectable Decorator
    participant SelectColumn as SelectColumn
    participant CheckboxDOM as Checkbox Component

    App->>Th: pass select props (isSelected, isIndeterminate, onSelect)
    Th->>Selectable: extraParams={ isIndeterminate, ... }
    Selectable->>SelectColumn: isIndeterminate={rowId === -1 ? isIndeterminate : undefined}
    SelectColumn->>SelectColumn: construct checkboxProps (includes isChecked: null if isIndeterminate)
    SelectColumn->>CheckboxDOM: render Checkbox with checkboxProps
    CheckboxDOM-->>App: renders checked/indeterminate/unchecked
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

  • #12404: Requests indeterminate state for the select-all header checkbox; this PR implements isIndeterminate and wiring to address that.
  • patternfly/patternfly-react#12410: Same gap—adds indeterminate support through types and component wiring as done here.

Suggested labels

Needs design review

Suggested reviewers

  • mcoker
  • thatblindgeye
  • kmcfaul
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature: adding indeterminate checkbox state support for the select-all header in the Table component.
Linked Issues check ✅ Passed All coding requirements from #12404 are met: ThSelectType extended with isIndeterminate, selectable decorator propagates it, and SelectColumn sets the DOM indeterminate property.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing indeterminate checkbox support; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@patternfly-build
Copy link
Copy Markdown
Collaborator

patternfly-build commented May 5, 2026

…header

Add support for indeterminate state to the Table component's select-all
checkbox, following PatternFly's bulk selection design guidelines.

The select-all checkbox now supports three states:
- Unchecked: no items selected
- Indeterminate: some items selected (shows dash/minus icon)
- Checked: all items selected

## Changes

- Add `isIndeterminate?: boolean` property to `ThSelectType` interface
- Add `isIndeterminate?: boolean` to `IColumn` extraParams type
- Update `Th` component to pass `isIndeterminate` to the selectable decorator
- Update `selectable` decorator to pass indeterminate state to `SelectColumn`
- Update `SelectColumn` to use PatternFly Checkbox's native indeterminate support (isChecked: null)
- Update `TableSelectable` example to demonstrate indeterminate state
- Add new `TableSelectableIndeterminate` example showcasing the feature

## Implementation

The indeterminate state is implemented using the PatternFly Checkbox component's
native support by setting `isChecked: null` when `isIndeterminate` is true.

## Usage

\`\`\`typescript
const areSomeReposSelected = selectedRepoNames.length > 0 && selectedRepoNames.length < selectableRepos.length;

<Th
  select={{
    onSelect: (_event, isSelecting) => selectAllRepos(isSelecting),
    isSelected: areAllReposSelected,
    isIndeterminate: areSomeReposSelected
  }}
  aria-label="Row select"
/>
\`\`\`

Fixes patternfly#12404

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@rhamilto rhamilto force-pushed the feat/table-indeterminate-checkbox branch from 3ab7def to 1b9740e Compare May 5, 2026 15:05
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/react-table/src/components/Table/SelectColumn.tsx (1)

47-61: 💤 Low value

checkboxProps duplicates all four fields from commonProps — consider eliminating the separate object.

PatternFly's Checkbox supports isChecked?: boolean | null, where null means the checkbox will be indeterminate (partially checked). The override is correct, but checkboxProps replicates all four fields (...props, id, ref, onChange) already present in commonProps. You can eliminate the duplication by building the conditional override directly at the call-site:

♻️ Proposed refactor
-  // PatternFly Checkbox supports indeterminate via isChecked: null
-  const checkboxProps = {
-    ...props,
-    id,
-    ref: inputRef,
-    onChange: handleChange,
-    ...(isIndeterminate && { isChecked: null })
-  };
-
   const commonProps = {
     ...props,
     id,
     ref: inputRef,
     onChange: handleChange
   };
-        <Checkbox {...checkboxProps} />
+        <Checkbox {...commonProps} {...(isIndeterminate && { isChecked: null })} />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/react-table/src/components/Table/SelectColumn.tsx` around lines 47 -
61, Remove the duplicated object by using commonProps as the base and applying
the indeterminate override only where Checkbox is rendered: delete the separate
checkboxProps declaration and, at the Checkbox render site, spread commonProps
and conditionally include isChecked: null when isIndeterminate is true
(preserving ...props, id, ref: inputRef, onChange: handleChange from
commonProps). Keep the identifier names isIndeterminate, commonProps and
checkbox behavior consistent with PatternFly's Checkbox which accepts
isChecked?: boolean | null.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/react-table/src/components/Table/SelectColumn.tsx`:
- Around line 47-61: Remove the duplicated object by using commonProps as the
base and applying the indeterminate override only where Checkbox is rendered:
delete the separate checkboxProps declaration and, at the Checkbox render site,
spread commonProps and conditionally include isChecked: null when
isIndeterminate is true (preserving ...props, id, ref: inputRef, onChange:
handleChange from commonProps). Keep the identifier names isIndeterminate,
commonProps and checkbox behavior consistent with PatternFly's Checkbox which
accepts isChecked?: boolean | null.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 407847d8-4ecd-4bbc-80dc-1d367e75dd63

📥 Commits

Reviewing files that changed from the base of the PR and between 90f963f and 1b9740e.

📒 Files selected for processing (8)
  • packages/react-table/src/components/Table/SelectColumn.tsx
  • packages/react-table/src/components/Table/TableTypes.tsx
  • packages/react-table/src/components/Table/Th.tsx
  • packages/react-table/src/components/Table/base/types.tsx
  • packages/react-table/src/components/Table/examples/Table.md
  • packages/react-table/src/components/Table/examples/TableSelectable.tsx
  • packages/react-table/src/components/Table/examples/TableSelectableIndeterminate.tsx
  • packages/react-table/src/components/Table/utils/decorators/selectable.tsx
✅ Files skipped from review due to trivial changes (2)
  • packages/react-table/src/components/Table/examples/TableSelectable.tsx
  • packages/react-table/src/components/Table/examples/Table.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/react-table/src/components/Table/utils/decorators/selectable.tsx
  • packages/react-table/src/components/Table/Th.tsx

@rhamilto
Copy link
Copy Markdown
Member Author

rhamilto commented May 5, 2026

cc: @nicolethoen, this is needed to complete openshift/console#16203

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Table: Add indeterminate checkbox state support for select-all header

2 participants