[feature] Add single-row-required selection mode to st.dataframe#14288
[feature] Add single-row-required selection mode to st.dataframe#14288sfc-gh-lmasuch merged 20 commits intodevelopfrom
single-row-required selection mode to st.dataframe#14288Conversation
Adds a new selection mode that ensures exactly one row is always selected (radio-like behavior). Auto-selects the first row when no default is provided, prevents clearing, and uses circle checkbox style for visual differentiation. Co-Authored-By: Claude Opus 4.6 <[email protected]>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
frontend/lib/src/components/widgets/DataFrame/hooks/useSelectionHandler.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
This PR adds a new st.dataframe selection mode, "single-row-required", to enforce radio-like behavior where exactly one row is always selected (defaulting to the first row) and clearing the selection is disallowed.
Changes:
- Extended the backend selection mode parsing/validation and selection-state serde to support
"single-row-required"and auto-select row 0 when needed. - Updated the frontend DataFrame selection handling/state initialization to prevent row deselection and render circle-style row markers.
- Added/updated unit and e2e coverage plus a product spec for the new mode.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| specs/2026-03-10-single-row-required-selection/product-spec.md | Product/behavior spec for required single-row selection mode. |
| proto/streamlit/proto/Dataframe.proto | Adds SINGLE_ROW_REQUIRED enum value to the Dataframe selection mode proto. |
| lib/streamlit/elements/arrow.py | Backend support: new mode literals, validation, proto mapping, and auto-select row 0 in required mode. |
| lib/tests/streamlit/elements/arrow_dataframe_test.py | Backend unit tests updated to include the new selection mode and required-mode validation behavior. |
| frontend/lib/src/components/widgets/DataFrame/hooks/useWidgetState.ts | Frontend widget initialization: auto-select row 0 for required mode when no stored/default selection exists. |
| frontend/lib/src/components/widgets/DataFrame/hooks/useWidgetState.test.ts | Updates existing tests for new function signature (but missing coverage for required-mode branch). |
| frontend/lib/src/components/widgets/DataFrame/hooks/useSelectionHandler.ts | Frontend selection processing updated to prevent clearing row selection in required mode. |
| frontend/lib/src/components/widgets/DataFrame/hooks/useSelectionHandler.test.ts | Adds tests for required-mode detection and “cannot clear” behavior. |
| frontend/lib/src/components/widgets/DataFrame/DataFrame.tsx | UI tweaks: hide clear-selection action (partially), and circle row markers for required mode. |
| e2e_playwright/st_dataframe_selections.py | Adds an app scenario exercising "single-row-required" mode. |
| e2e_playwright/st_dataframe_selections_test.py | E2E behavior + snapshot coverage for required single-row selection mode. |
Comments suppressed due to low confidence (1)
frontend/lib/src/components/widgets/DataFrame/DataFrame.tsx:738
- The “Clear selection” toolbar action is still shown when
isRequiredRowSelectionActivatedis true and a column/cell selection exists. Clicking it callsclearSelection()which clears row selection too, violating the single-row-required invariant (and the spec statement that the clear action should be hidden). Either hide this action unconditionally when required mode is active, or adjust the clear behavior to preserve the required row selection.
{((isRowSelectionActivated &&
isRowSelected &&
!isRequiredRowSelectionActivated) ||
(isColumnSelectionActivated && isColumnSelected) ||
(isCellSelectionActivated && isCellSelected)) && (
// Add clear selection action if selections are active
// and a valid selections currently exists. Cell selections
// are not relevant since they are not synced to the backend
// at the moment. Hide for single-row-required mode since
// clearing is not allowed.
<ToolbarAction
label="Clear selection"
icon={Close}
onClick={() => {
clearSelection()
clearTooltip()
}}
/>
single-row-required selection mode to st.dataframe
- Fix clearSelection to preserve row selection in single-row-required mode (prevents sorting columns from clearing the required row selection) - Update RangeIndex hiding to include single-row-required mode - Add unit test for clearSelection behavior in single-row-required mode Co-Authored-By: Claude Opus 4.6 <[email protected]>
## Describe your changes Automated snapshot updates for #14288 created via the snapshot autofix CI workflow. This workflow was triggered by adding the `update-snapshots` label to a PR after Playwright E2E tests failed with snapshot mismatches. **Updated snapshots:** 6 file(s)⚠️ **Please review the snapshot changes carefully** - they could mask visual bugs if accepted blindly. This PR targets a feature branch and can be merged without review approval. Co-authored-by: Streamlit Bot <[email protected]>
## Describe your changes Automated snapshot updates for #14288 created via the snapshot autofix CI workflow. This workflow was triggered by adding the `update-snapshots` label to a PR after Playwright E2E tests failed with snapshot mismatches. **Updated snapshots:** 1 file(s)⚠️ **Please review the snapshot changes carefully** - they could mask visual bugs if accepted blindly. This PR targets a feature branch and can be merged without review approval. Co-authored-by: Streamlit Bot <[email protected]>
## Describe your changes Automated snapshot updates for #14288 created via the snapshot autofix CI workflow. This workflow was triggered by adding the `update-snapshots` label to a PR after Playwright E2E tests failed with snapshot mismatches. **Updated snapshots:** 1 file(s)⚠️ **Please review the snapshot changes carefully** - they could mask visual bugs if accepted blindly. This PR targets a feature branch and can be merged without review approval. Co-authored-by: Streamlit Bot <[email protected]>
SummaryThis PR adds a new Code QualityThe implementation is well-structured and follows existing codebase patterns. The Issues identified (by reviewer agreement level):
Test CoverageCoverage is solid across all layers:
Gaps identified (by reviewer agreement):
Backwards CompatibilityAll three reviewers agree: this is a fully backwards-compatible, additive change. Existing selection modes are unaffected. The new mode is opt-in and mutually exclusive with other row modes (enforced by validation). Security & RiskAll three reviewers agree: no security concerns. Changes are confined to dataframe selection logic with no impact on routing, auth, sessions, WebSocket transport, embedding, or external assets. External test recommendation
AccessibilityAll three reviewers agree: no accessibility regressions. The circle checkbox ( RecommendationsMust-fix before merge:
Nice-to-have:
Reviewer Agreement Summary
The consolidation model ( VerdictCHANGES REQUESTED: Two of three reviewers requested changes. While the implementation is solid and well-structured, three gaps should be addressed before merge: (1) the missing docstring for the new selection mode (users can't discover the feature), (2) missing This is a consolidated AI review by 📋 Review by `gemini-3.1-pro`SummaryThis PR introduces a new Code QualityThe code changes are well-structured, clear, and follow the existing patterns in the codebase.
Test CoverageThe changes are comprehensively tested:
Backwards CompatibilityThis is a non-breaking, additive change. Existing selection modes ( Security & RiskNo security concerns or regression risks were identified. The changes are confined to the dataframe selection logic and do not interact with security-sensitive areas such as routing, authentication, or external assets. External test recommendation
AccessibilityThe frontend changes rely on RecommendationsThe implementation is solid and ready to be merged. No further changes are required. VerdictAPPROVED: The implementation is complete, well-tested, and follows the project's best practices. This is an automated AI review by 📋 Review by `gpt-5.3-codex-high`SummaryThis PR introduces a new Code QualityI found one blocking behavior issue:
Test CoverageCoverage is generally solid across backend + frontend hook tests + e2e scenarios for default selection, preventing clear, and visual behavior.
Backwards CompatibilityThe API change is additive ( Security & RiskNo direct security-sensitive surfaces are modified (no auth/session/websocket handshake/routes/CORS/cookie/header changes). External test recommendation
AccessibilityNo accessibility regressions are obvious in this diff. Recommendations
VerdictCHANGES REQUESTED: The feature is close, but sorting with This is an automated AI review by 📋 Review by `opus-4.6-thinking`SummaryThis PR adds a new
Code QualityThe implementation is well-structured and follows existing patterns throughout the codebase. The layered approach (proto -> backend -> frontend) is clean, and the Specific notes:
Test CoveragePython unit tests (
TypeScript unit tests (
Gaps identified:
E2E tests (
The E2E test uses Backwards CompatibilityThis change is fully backwards compatible:
Security & RiskNo security concerns identified:
External test recommendation
Accessibility
Recommendations
VerdictCHANGES REQUESTED: Solid, well-structured feature implementation with good test coverage across all layers. The main gaps are a missing docstring update for the new selection mode (item 2 — users won't discover the feature without it), a missing This is an automated AI review by |
- Add "single-row-required" to selection_mode docstring in arrow.py - Add typing test for selection_mode="single-row-required" - Add useWidgetState unit test for auto-selection in required mode - Fix unnecessary backend sync when row clear is prevented Co-Authored-By: Claude Opus 4.6 <[email protected]>
SummaryThis PR adds a new
Code QualityAll three reviewers agree that the code is well-structured and follows existing codebase patterns. Notable strengths:
Minor observations (non-blocking):
Test CoverageAll three reviewers agree that test coverage is thorough and well-organized across all layers. This was the strongest point of consensus.
One area for improvement: the E2E sort preservation test ( Backwards CompatibilityAll three reviewers agree: no backwards compatibility concerns.
Security & RiskAll three reviewers agree: no security concerns identified. Changes are confined to UI selection logic — no new endpoints, auth changes, external requests, HTML/Markdown rendering changes, or new dependencies. External test recommendation
AccessibilityAll three reviewers agree the accessibility aspects are handled well:
Reviewer Consensus
Unique findings by reviewer:
No conflicts between reviewers; all agree on the core assessment with different reviewers surfacing complementary minor observations. Recommendations
VerdictAPPROVED: All three reviewers unanimously approve. The implementation is robust, well-tested across all layers (backend, frontend, E2E), follows existing codebase patterns, and introduces no backwards compatibility or security concerns. The minor suggestions above are non-blocking refinements that could be addressed in a follow-up. This is a consolidated AI review by 📋 Review by `gemini-3.1-pro`SummaryThis PR introduces a new Code QualityThe code changes are clean, well-structured, and follow the existing patterns in the codebase.
Test CoverageTest coverage is excellent.
Backwards CompatibilityThe changes are fully backwards compatible. The new Security & RiskNo security concerns or regression risks identified. The changes are confined to the dataframe element's frontend and backend state management and do not interact with security-sensitive areas such as routing, authentication, or cross-origin behavior. External test recommendation
AccessibilityThe frontend changes include a thoughtful accessibility improvement: using RecommendationsNone. The implementation is solid and ready for merge. VerdictAPPROVED: The implementation of the This is an automated AI review by 📋 Review by `gpt-5.3-codex-high`SummaryThis PR adds a new Code QualityThe implementation is cohesive and follows existing patterns across backend validation ( One non-blocking docs consistency nit:
Test CoverageCoverage is strong and multi-layered for this change:
Given the scope, this is sufficient for merge confidence. Backwards CompatibilityNo breaking API changes were identified:
Behavioral change is additive and opt-in via Security & RiskNo security-sensitive surfaces were modified (no auth/session routing, cookies/CSRF, asset handlers, external fetches, dynamic code execution, or sensitive data handling changes). Risk is primarily functional UI/state synchronization, and current tests cover those paths well. External test recommendation
AccessibilityNo clear accessibility regressions were found in this diff. The change mainly affects canvas-rendered row marker styling ( Recommendations
VerdictAPPROVED: The feature implementation is coherent, well-tested across backend/frontend/e2e layers, and appears ready to merge with only a minor documentation consistency follow-up. This is an automated AI review by 📋 Review by `opus-4.6-thinking`SummaryThis PR adds a new
Code QualityThe code is well-structured and follows existing patterns in the codebase. Strengths:
Minor observations:
Test CoverageTest coverage is thorough and well-organized across all layers:
The E2E sort test ( Backwards CompatibilityNo backwards compatibility concerns:
Security & RiskNo security concerns identified:
External test recommendation
Accessibility
Recommendations
VerdictAPPROVED: Well-implemented feature with thorough test coverage across all layers, no backwards compatibility or security concerns, and clean integration with existing selection infrastructure. The minor suggestions above are non-blocking refinements. This is an automated AI review by |
| { | ||
| id: element.id, | ||
| formId: element.formId, | ||
| } as WidgetInfo, |
There was a problem hiding this comment.
question: Is this cast necessary? If not, remove it.
There was a problem hiding this comment.
Improved it a bit, but still need a case for element.id
| // no stored selection and no explicit default. | ||
| if (isRequiredRowSelectionActivated && originalNumRows > 0) { | ||
| const defaultRequiredSelection: GridSelection = { | ||
| rows: CompactSelection.empty().add(0), |
There was a problem hiding this comment.
question: Is this 0 guaranteed to be the same as selection: rows: [0]? Are they both guaranteed to be both the row at data index 0 or the row at display index 0? I'm thinking about the use case where the table is sorted and thus data index 0 !== display index 0.
There was a problem hiding this comment.
Yep, it's guaranteed to be the same row since this only runs in loadInitialSelectionState before any sorting is applied
SummaryThis PR introduces a new Key behaviors: auto-selects the first row when no default is provided, prevents clearing the row selection, uses a circle checkbox style for visual differentiation, hides the "Clear selection" toolbar button, preserves row selection through column sort operations by remapping display indices, and can be combined with column/cell selection modes. Reviewer Consensus
All three reviewers agreed on:
Key disagreement: gpt-5.3-codex-high identified a sorting consistency issue between the header-click and column-menu sort paths that the other two reviewers did not flag as blocking. After independent verification, this issue is confirmed valid — the Cross-Cutting ConcernsSort remap inconsistency (confirmed): The E2E test robustness: Both opus-4.6-thinking and the inline comments note that VerdictCHANGES_REQUESTED: The column-menu sort path missing the row selection remap is a real behavioral inconsistency that should be fixed before merge. The fix is straightforward (apply the same Consolidated review by This review also includes 4 inline comment(s) on specific code lines. Inline comments (4) that could not be posted on specific lines
if (isRequiredRowSelectionActivated && isRowSelected) {
const originalRowIndices = gridSelection.rows.toArray().map(getOriginalIndex)
pendingRowSelectionRemapRef.current = originalRowIndices
clearSelection(true, true)
} else if (isRowSelectionActivated && isRowSelected) {
clearSelection(false, true)
} else {
clearSelection(true, true)
}
|
- Add row selection remapping for column-menu sort in single-row-required mode (matches existing header-click sort behavior) - Improve E2E test to verify specific row index after sort, not just any row - Remove unnecessary `as WidgetInfo` type assertions in useWidgetState Co-Authored-By: Claude Opus 4.6 <[email protected]>
Schedule the row selection remapping via useTimeout(0ms) instead of useEffect to ensure getOriginalIndex reflects the sorted state. Also captures column/cell selection at sort time to avoid stale refs. Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Summary
This PR introduces a new single-row-required selection mode for st.dataframe that ensures exactly one row is always selected, providing radio-button-like behavior. The implementation spans the full stack: a new protobuf enum value (SINGLE_ROW_REQUIRED = 6), Python backend validation and auto-selection logic in arrow.py, frontend selection handling in useSelectionHandler.ts and useWidgetState.ts, visual differentiation via circular checkbox markers in DataFrame.tsx, and comprehensive tests at all layers (Python unit, frontend unit, and E2E).
Code Quality
The code is well-structured and follows existing patterns for selection handling throughout. The new mode integrates cleanly into the existing selection infrastructure with clear separation of concerns between the hook layer (useSelectionHandler, useWidgetState) and the component layer (DataFrame).
One correctness issue was identified in the sort/remap path in DataFrame.tsx. Both sort handlers (column-header click and column-menu sort) use clearSelection(true, false), which unnecessarily clears column selections and triggers a redundant backend sync with incorrect intermediate state before performRowSelectionRemap restores them. Additionally, gridSelection.current (cell selection) is captured and restored after sorting without remapping its row index, meaning a stale cell selection could point to different data post-sort. All three reviewers that completed their review agreed this is a blocking issue. See inline comments for specific remediation.
Test Coverage
Test coverage is excellent across all layers:
- Python unit tests (
arrow_dataframe_test.py): Cover the new selection mode parsing, validation, auto-selection of the first row, and edge cases (empty dataframes, invalid row indices). - Frontend unit tests (
useSelectionHandler.test.ts,useWidgetState.test.ts): Thoroughly test the new mode including required-row detection, prevention of row clearing, auto-selection of the first row, and combined row+column behavior. - E2E tests (
st_dataframe_selections_test.py): Comprehensive Playwright tests verifying auto-selection, visual style (via snapshots across browsers), keyboard interactions (Escape key not clearing required selection), combined multi-column selections, and sorting behavior. - Type tests (
dataframe_types.py): Updated to include the new selection mode literal.
One gap noted: a targeted regression test for sort behavior when single-row-required is combined with cell selection mode(s) would strengthen confidence, particularly given the current restoration issue identified above.
Backwards Compatibility
No breaking changes. The new feature is opt-in via the "single-row-required" literal value for the selection_mode parameter. Existing selection modes ("single-row", "multi-row", "single-column", etc.) retain their current behavior. The protobuf enum extension is additive and compatible with existing values.
Security & Risk
No security concerns identified. Changes are confined to the dataframe element's selection state management and UI rendering. No modifications to routing, authentication, session management, WebSocket transport, file handling, or external asset serving. Input validation in _validate_selection_state correctly handles edge cases.
The primary risk is behavioral regression in the frontend selection remapping logic during sorting, as detailed in the Code Quality section.
External test recommendation
- Recommend external_test: No
- Triggered categories: None
- Evidence: The PR only modifies
st.dataframeselection logic, protobuf enum, and React state handling. No changes to routing, auth, WebSocket transport, embedding, cross-origin behavior, security headers, or external asset serving. - Suggested external test focus areas: N/A
- Confidence: High — all three completed reviews unanimously agreed no external test coverage is needed.
Accessibility
The circular checkbox style (checkboxStyle: "circle") provides a clear visual affordance that the selection behaves like a radio button (single required choice), which is a good accessibility practice. Keyboard interaction is correctly handled — the Escape key does not clear the required selection. No new non-semantic interactive DOM controls were introduced.
Recommendations
- Fix sort handler
clearSelectioncalls: In both sort handlers inDataFrame.tsx(column-header click ~line 992 and column-menu sort ~line 1204), changeclearSelection(true, false)toclearSelection(true, true)to preserve column selections and avoid a redundant backend sync with incorrect intermediate state. - Stop restoring stale cell selection after sort: Set
current: undefinedinpendingRowSelectionRemapRefinstead of capturinggridSelection.current, since cell selection row indices become invalid after sorting. - Add regression test: Add a targeted test for sort behavior when
single-row-requiredis combined with cell selection to prevent recurrence of thecurrentrestoration issue.
Verdict
CHANGES_REQUESTED: The feature is well-implemented with excellent test coverage, but a correctness issue in the sort/remap path — redundant backend syncs and stale cell selection restoration — needs to be addressed before merge. All completed reviews agreed on this assessment.
Review metadata
Reviewed by: gemini-3.1-pro, gpt-5.3-codex-high (consolidated by claude-4.6-opus-high-thinking)
Missing reviews: claude-4.6-opus-high-thinking failed to complete its individual review (note: this model served as consolidator instead).
Reviewer agreement: Both completed reviews independently identified the same blocking issue in the sort/remap path and agreed on all other assessments (test coverage, backwards compatibility, security, external test recommendation, accessibility). No disagreements to resolve.
This is an automated AI review consolidated by claude-4.6-opus-high-thinking. Please verify the feedback and use your judgment.
This review also includes 2 inline comment(s) on specific code lines.
Address AI review feedback: use clearSelection(true, true) instead of clearSelection(true, false) to preserve both row and column selections during sorting in single-row-required mode. This avoids an intermediate state where columns are cleared then restored via remap, causing two backend syncs. Also set current: undefined in pending remap ref since cell selection coordinates become stale after sorting. Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Summary
This PR adds a new "single-row-required" selection mode to st.dataframe that enforces exactly one row is always selected (radio-like behavior). The changes span the full stack: a new protobuf enum value (SINGLE_ROW_REQUIRED = 6), Python backend auto-selection/validation logic, frontend selection handling (prevention of clearing, sort-remap preservation, circle checkbox style, toolbar button hiding), and comprehensive tests across all layers.
Reviewer consensus: All three reviewers (claude-4.6-opus-high-thinking, gemini-3.1-pro, gpt-5.3-codex-high) approved this PR unanimously. There were no disagreements on any findings.
Code Quality
The implementation is well-structured and follows existing Streamlit codebase patterns. All reviewers agreed on the high quality of the code. Specific positives noted:
- Good use of
_ROW_SELECTION_MODESset to consolidate row mode checks and avoid scattered string comparisons. - The
useTimeout+callbackRefpattern for sort-remap correctly avoids stale closure issues — praised by multiple reviewers as "pragmatic and well-documented." isRequiredRowSelectionActivatedis derived during render (not via effect), following React best practices.- The
WidgetInfotype assertion cleanup (as WidgetInfo→?? undefined) is a welcome incidental improvement.
One reviewer (claude) noted that the sort-remap logic in DataFrame.tsx is duplicated between onHeaderClicked (~line 979) and the ColumnMenu's onSortColumn callback (~line 1193). While this follows the existing pattern for these two code paths, extracting a shared helper would improve maintainability. This is captured as an inline comment and is non-blocking.
Test Coverage
All reviewers rated test coverage as strong to excellent. Coverage spans:
- Python unit tests: Auto-selection, valid selection preservation, empty dataframe edge case, single-row limit, combined modes, and invalid mode combinations.
- TypeScript unit tests: Mode detection, clearing prevention, selection change,
clearSelectionpreservation, and combined row+column mode sync. - E2E tests: Auto-selection on load, no-clear via Escape, no-deselect on same-row click, row change, sort preservation, visual snapshot, and combined mode with programmatic control.
- Type tests: Added
assert_typefor the new selection mode.
The E2E tests include a few wait_for_timeout calls, which are generally discouraged. However, the inline comments justify this with the canvas-based rendering of glide-data-grid making DOM-based assertions unreliable for timing — all reviewers found this to be a reasonable exception.
Backwards Compatibility
Fully backwards compatible — all reviewers agreed unanimously:
- The protobuf change is additive (new enum value
6); older clients simply ignore it. - The new
"single-row-required"string literal extends the existingSelectionModeunion without affecting existing modes. - Existing
_validate_selection_stateandDataframeSelectionSerdebehavior is unchanged for existing modes.
Security & Risk
No security concerns identified by any reviewer. The changes are confined to the DataFrame widget's selection handling:
- No new network endpoints, external requests, or file I/O.
- No changes to authentication, CORS, CSP, or session management.
- No dynamic code execution (
eval,exec, etc.). - Input validation properly sanitizes row indices and enforces bounds.
External test recommendation
- Recommend external_test: No
- Triggered categories: None
- Evidence: All changes are within the
st.dataframewidget's selection logic (protobuf enum, Python selection mode handling, React hooks, and grid rendering). No routing, auth, WebSocket, embedding, asset serving, cross-origin, storage, or security header changes. - Confidence: High (unanimous across all reviewers)
- Assumptions and gaps: None — the feature is self-contained within the DataFrame widget.
Accessibility
- The circle checkbox style for
single-row-requiredmode provides visual differentiation from square checkboxes (multi-row mode), correctly conveying radio-like semantics. - The existing
rowMarkersconfiguration with"checkbox-visible"kind maintains keyboard accessibility. - The "Clear selection" toolbar button is correctly hidden (removed from DOM, not just visually), avoiding confusion for screen reader users.
- The underlying accessibility of canvas elements is handled by
glide-data-grid, which remains unchanged.
Recommendations
- [Non-blocking] Consider extracting the duplicated sort-remap logic in
DataFrame.tsx(in bothonHeaderClickedandonSortColumn) into a shared helper function to reduce code duplication and maintenance risk. - [Non-blocking] The
DataframeSelectionStatedocstring (inarrow.py) contains a warning that "row selections will be reset" on sort, which is no longer fully accurate forsingle-row-requiredmode where selections are preserved. Consider updating to note the exception.
Verdict
APPROVED: Well-implemented feature with comprehensive test coverage, correct handling of edge cases (sort, clear, combined modes), full backwards compatibility, and no security concerns. All three reviewers approved unanimously. The duplicated sort-remap logic and minor docstring gap are non-blocking suggestions for future improvement.
This is a consolidated AI review by claude-4.6-opus-high-thinking, synthesizing reviews from: claude-4.6-opus-high-thinking, gemini-3.1-pro, gpt-5.3-codex-high (3/3 expected models completed).
This review also includes 3 inline comment(s) on specific code lines.
Describe your changes
Adds
single-row-requiredselection mode tost.dataframethat ensures exactly one row is always selected (radio-like behavior):Auto-selects the first row when no default is provided
Prevents clearing the selection (only allows changing to a different row)
Uses circle checkbox style for visual differentiation from square checkboxes
Hides the "Clear selection" toolbar button
Demo
Product spec
Open Questions:
Github Issues
Testing Plan
lib/tests/streamlit/elements/arrow_dataframe_test.pyuseSelectionHandler.test.ts,useWidgetState.test.tse2e_playwright/st_dataframe_selections_test.pyContribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.
Agent metrics