Skip to content

Add select all and select x matches (select all 2)#13795

Merged
sfc-gh-dmatthews merged 12 commits intodevelopfrom
02-02-select-all-feature
Feb 16, 2026
Merged

Add select all and select x matches (select all 2)#13795
sfc-gh-dmatthews merged 12 commits intodevelopfrom
02-02-select-all-feature

Conversation

@sfc-gh-dmatthews
Copy link
Copy Markdown
Contributor

@sfc-gh-dmatthews sfc-gh-dmatthews commented Feb 3, 2026

Describe your changes

This PR adds a "Select all" and "Select X matches" feature to the Multiselect widget. When the dropdown is open:

  • Without a search filter: Shows "Select all" option to select all remaining unselected options, but only if there is more than one item
  • With a search filter: Shows "Select X matches" option to select all filtered matches, but only if there is more than one match in the filtered list

No styling changes are applies in this PR. That's next in the Graphite stack.

Screenshot or video (only for visual changes)

Select allSelect X matches
image image
image image

GitHub Issue Link (if applicable)

Closes #4714

Testing Plan

  • Explanation of why no additional tests are needed
  • Unit Tests (JS and/or Python)
  • E2E Tests
  • Any manual testing needed?

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@snyk-io
Copy link
Copy Markdown
Contributor

snyk-io bot commented Feb 3, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 3, 2026

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-13795/streamlit-1.54.0-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-13795.streamlit.app (☁️ Deploy here if not accessible)

Copy link
Copy Markdown
Contributor Author

sfc-gh-dmatthews commented Feb 3, 2026

@sfc-gh-dmatthews sfc-gh-dmatthews changed the title Add select all and select x matches Add backend piping for select-all feature Feb 3, 2026
@sfc-gh-dmatthews sfc-gh-dmatthews changed the title Add backend piping for select-all feature Add select all and select x matches Feb 3, 2026
@sfc-gh-dmatthews sfc-gh-dmatthews changed the title Add select all and select x matches Add select all and select x matches (select all 2) Feb 3, 2026
@sfc-gh-dmatthews sfc-gh-dmatthews added change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users security-assessment-completed ai-review If applied to PR or issue will run AI review workflow labels Feb 3, 2026
@github-actions github-actions bot removed the ai-review If applied to PR or issue will run AI review workflow label Feb 3, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 3, 2026

Summary

This PR adds a "Select all" and "Select X matches" feature to the Multiselect widget. When the dropdown is open:

  • Without a search filter: Shows "Select all" option to select all remaining unselected options
  • With a search filter: Shows "Select X matches" option to select all filtered matches

The implementation is clean and the unit tests are comprehensive.

Code Quality

The implementation in Multiselect.tsx is well-structured:

  1. Good separation of concerns: The filterOptions callback handles the UI logic of when to show "Select all" vs "Select X matches", while the generateNewState callback handles the actual selection logic.

  2. Proper use of refs: The selectMatchesRef is used to store filtered matches for the "Select X matches" option, avoiding race conditions that could occur if the values were computed inline.

  3. Edge case handling: The code correctly handles:

    • Only shows bulk selection options when there are >1 selectable options
    • Respects maxSelections limit
    • Distinguishes between search vs. no-search states
  4. Reuses existing constants: Uses SELECT_ALL_ID and SELECT_MATCHES_ID from the shared Dropdown component, maintaining consistency.

Minor observation in Multiselect.tsx:244-255:

  • The filtering logic stores values in selectMatchesRef on every filter call. This is necessary due to the callback-based architecture, but the comment accurately explains this design decision.

Test Coverage

Unit Tests (Frontend)

The unit test coverage is excellent:

  1. Comprehensive new test suite: The "Select all and Select X matches" test suite (Multiselect.test.tsx:611-897) covers:

    • Selecting all from empty state
    • Selecting all when some options are already selected
    • Selecting matching options with search filter
    • maxSelections being respected for both "Select all" and "Select X matches"
    • Edge cases (0 options, 1 option, clearing search)
    • Mutually exclusive behavior (never shows both "Select all" and "Select X matches")
  2. Existing tests updated correctly: Tests that check dropdown options now account for the new "Select all" option being first in the list.

  3. Good negative assertions: Tests verify that "Select all" and "Select X matches" do NOT appear in inappropriate situations.

E2E Tests

Missing E2E test coverage: The PR does not include E2E tests for the new feature. While the unit tests are comprehensive, E2E tests would verify:

  • Visual appearance of "Select all" option
  • Integration with the full Streamlit stack
  • Behavior across different browsers

Potential E2E test breakage: Some existing E2E tests may fail due to the new "Select all" option changing dropdown item counts:

  • st_multiselect_test.py:157 - expect(dropdown_elements).to_have_count(2) expects exactly 2 items for a 2-option multiselect. With "Select all", this would be 3.
  • st_multiselect_test.py:379 - expect(options_list).to_have_count(4) may need adjustment.

Backwards Compatibility

Low risk of breaking changes:

  • The feature is purely additive - existing functionality is preserved
  • The "Select all" option only appears when there are 2+ selectable options
  • Single-option multiselects behave exactly as before
  • The order preservation of existing options is maintained (new option is prepended)

One subtle behavioral change: Users who relied on the first dropdown item being the first data option will now see "Select all" first. This is unlikely to cause issues in practice.

Security & Risk

No security concerns identified:

  • The feature operates entirely on existing option data
  • No new user input handling that could introduce XSS or injection vulnerabilities
  • The SELECT_ALL_ID and SELECT_MATCHES_ID are internal constants, not exposed to users

Low regression risk:

  • The core selection logic in generateNewState is extended with new cases but existing cases are untouched
  • The filtering logic is isolated in filterOptions

Recommendations

  1. Verify E2E tests pass: Run the existing E2E tests to confirm they still pass with the new "Select all" option. If not, update the expected counts:

    • st_multiselect_test.py:157 may need to change from to_have_count(2) to to_have_count(3)
    • Similar adjustments may be needed elsewhere
  2. Consider adding E2E test coverage: Add at least one E2E test for the "Select all" functionality to catch visual regressions:

    def test_multiselect_select_all(app: Page):
        """Should select all options when clicking Select all."""
        ms = get_multiselect(app, "multiselect 1")
        ms.locator("input").click()
        app.locator("li").filter(has_text="Select all").click()
        wait_for_app_run(app)
        expect_text(app, "value 1: ['male', 'female']")
  3. Add snapshot test for dropdown with "Select all": Consider adding a screenshot test showing the "Select all" option in the dropdown.

  4. PR description is sparse: The PR body template fields (Testing Plan, etc.) are not filled in. Adding details about the testing approach would help reviewers.

Verdict

APPROVED: The implementation is clean, well-tested with comprehensive unit tests, and follows existing patterns. The feature adds valuable UX improvement without breaking existing functionality. The main gap is missing E2E test updates/additions, which should be verified before merge to ensure CI passes.


This is an automated AI review using opus-4.5-thinking. Please verify the feedback and use your judgment.

Copy link
Copy Markdown
Collaborator

@sfc-gh-bnisco sfc-gh-bnisco left a comment

Choose a reason for hiding this comment

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

Small test suggestion inline, and given the e2e failures, looks like there will need to be some revisions on the e2e tests.

@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 02-02-multiselect-selection-plumbing branch from 8096ee9 to 7132679 Compare February 3, 2026 17:11
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 02-02-select-all-feature branch from 98d61dc to 57ceb89 Compare February 3, 2026 17:11
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 3, 2026

📈 Frontend coverage change detected

The frontend unit test (vitest) coverage has increased by 0.0900%

  • Current PR: 87.0700% (14042 lines, 1815 missed)
  • Latest develop: 86.9800% (14033 lines, 1826 missed)

🎉 Great job on improving test coverage!

📊 View detailed coverage comparison

@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-select-all-feature branch from f876deb to 2df8686 Compare February 3, 2026 18:38
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from 7132679 to 44abccb Compare February 3, 2026 18:38
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-select-all-feature branch from 90a9eeb to b744651 Compare February 3, 2026 21:39
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from 44abccb to 93808e8 Compare February 3, 2026 21:39
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-select-all-feature branch from b744651 to 127163f Compare February 3, 2026 23:55
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from 93808e8 to 0adf09d Compare February 3, 2026 23:55
@sfc-gh-dmatthews sfc-gh-dmatthews marked this pull request as ready for review February 4, 2026 00:41
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-select-all-feature branch from 127163f to edcd9fc Compare February 4, 2026 02:46
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch 2 times, most recently from 9b8a906 to 67426a6 Compare February 4, 2026 07:13
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from af34d22 to 98055e5 Compare February 12, 2026 19:54
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from 98055e5 to de31a73 Compare February 12, 2026 21:18
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-select-all-feature branch 2 times, most recently from 4c3152a to 4da12c9 Compare February 13, 2026 06:35
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from de31a73 to 904afcb Compare February 13, 2026 06:35
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from 904afcb to ab76d8e Compare February 15, 2026 04:33
Copy link
Copy Markdown
Contributor Author

sfc-gh-dmatthews commented Feb 16, 2026

Merge activity

  • Feb 16, 9:33 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Feb 16, 9:34 PM UTC: Graphite couldn't merge this pull request because a downstack PR Define selection constants (select all 1) #13794 failed to merge.
  • Feb 16, 11:04 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Feb 16, 11:06 PM UTC: Graphite rebased this pull request as part of a merge.
  • Feb 16, 11:23 PM UTC: Graphite couldn't merge this PR because it was not satisfying all requirements (Failed CI: 'playwright-e2e-tests').
  • Feb 16, 11:48 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Feb 16, 11:49 PM UTC: @sfc-gh-dmatthews merged this pull request with Graphite.

@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-multiselect-selection-plumbing branch from ab76d8e to 9465966 Compare February 16, 2026 21:53
@sfc-gh-dmatthews sfc-gh-dmatthews changed the base branch from 02-02-multiselect-selection-plumbing to graphite-base/13795 February 16, 2026 23:05
@sfc-gh-dmatthews sfc-gh-dmatthews changed the base branch from graphite-base/13795 to develop February 16, 2026 23:05
@sfc-gh-dmatthews sfc-gh-dmatthews merged commit 898560c into develop Feb 16, 2026
43 of 44 checks passed
@sfc-gh-dmatthews sfc-gh-dmatthews deleted the 02-02-select-all-feature branch February 16, 2026 23:49
lukasmasuch pushed a commit that referenced this pull request Feb 20, 2026
## Describe your changes
This PR adds a "Select all" and "Select X matches" feature to the Multiselect widget. When the dropdown is open:

- Without a search filter: Shows "Select all" option to select all remaining unselected options, but only if there is more than one item
- With a search filter: Shows "Select X matches" option to select all filtered matches, but only if there is more than one match in the filtered list

No styling changes are applies in this PR. That's next in the Graphite stack. 

## Screenshot or video (only for visual changes)
<table>
<tr><th>Select all</th><th>Select X matches</th></tr>
<tr>
<td>
<img width="772" height="205" alt="image" src="https://github.com/user-attachments/assets/713bd6d2-7645-4b2b-a323-21dd9f25ca88" />
</td>
<td>
<img width="766" height="207" alt="image" src="https://github.com/user-attachments/assets/960f3f7a-1c52-45d4-b382-e29ecbc39a92" />
</td>
</tr>
<tr>
<td>
<img width="787" height="210" alt="image" src="https://github.com/user-attachments/assets/e68c81df-d418-4f5d-8021-f254d8a40926" />
</td>
<td>
<img width="759" height="211" alt="image" src="https://github.com/user-attachments/assets/9deb0402-5880-4d86-9358-b82d41373f9c" />
</tr>
</table>

## GitHub Issue Link (if applicable)

Closes #4714

## Testing Plan

- Explanation of why no additional tests are needed
- Unit Tests (JS and/or Python)
- E2E Tests
- Any manual testing needed?

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.
@henrik-b
Copy link
Copy Markdown

I don't agree to "Users who relied on the first dropdown item being the first data option will now see "Select all" first. This is unlikely to cause issues in practice.".

In my case there are hundreds of options, and selecting all of them may cause a huge amount of data to be loaded, potentially crashing the Streamlit Server.

How can we switch off the new feature?

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

Labels

change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add select all shortcut or button for multiselect

3 participants