Skip to content

[fix] Programmatically closed popovers/expanders reopening on interaction with another#14945

Merged
sfc-gh-lwilby-1 merged 2 commits into
developfrom
fix/popover-expander-programmatic-close-stale-state
May 11, 2026
Merged

[fix] Programmatically closed popovers/expanders reopening on interaction with another#14945
sfc-gh-lwilby-1 merged 2 commits into
developfrom
fix/popover-expander-programmatic-close-stale-state

Conversation

@kmcgrady

@kmcgrady kmcgrady commented Apr 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes Programmatically closed popovers reopen when interacting with another stateful popover #14943 — programmatically closed popovers reopen when interacting with another stateful popover
  • When st.session_state.key = False closes a popover/expander, the frontend's WidgetStateManager was not updated, leaving a stale true value that got sent back to the backend on the next rerun
  • Added widgetMgr.setBoolValue(..., { fromUi: false }) to sync the widget manager when the backend overrides the open/expanded state, without triggering an additional rerun
  • Applied the same fix to st.expander which had the identical latent bug

Test plan

  • Updated Popover unit test ("syncs open state when element.open changes programmatically") to verify widget manager sync
  • Added Popover unit test ("syncs widget manager state on programmatic close to prevent stale reopens")
  • Added Expander unit test ("syncs widget manager state on programmatic expand change")
  • Added Expander unit test ("syncs widget manager state on programmatic collapse to prevent stale reopens")
  • Added Popover E2E test (test_programmatic_close_does_not_reopen_other_popover)
  • Added Expander E2E test (test_programmatic_close_does_not_reopen_other_expander)
  • All existing Popover/Expander unit tests pass (49/49)
  • Both new E2E tests pass
  • Verified manually via Playwright against make debug that the fix resolves the reported issue

🤖 Generated with Claude Code

Made with Orca 🐋

#14943)

When a popover or expander was closed programmatically via
st.session_state.key = False, the frontend updated its local React state
but did not update the WidgetStateManager. On the next rerun (triggered
by another widget), the stale "open=true" value was sent back to the
backend, causing the closed popover/expander to reopen.

Fix: call widgetMgr.setBoolValue with fromUi=false when the backend
overrides the open/expanded state, keeping the widget manager in sync
without triggering an additional rerun.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
Copilot AI review requested due to automatic review settings April 27, 2026 19:58
@snyk-io

snyk-io Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

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

Status Scan Engine 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

github-actions Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

✅ PR preview is ready!

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

@sfc-gh-kmcgrady sfc-gh-kmcgrady added change:bugfix PR contains bug fix implementation impact:users PR changes affect end users ai-review If applied to PR or issue will run AI review workflow labels Apr 27, 2026
@greptile-apps

greptile-apps Bot commented Apr 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a stale-state bug where programmatically closing a stateful popover or expander (via st.session_state.key = False) left a stale true value in the frontend's WidgetStateManager. On the next rerun triggered by another widget, that stale value was sent back to the backend, causing the closed component to reopen.

The fix adds a widgetMgr.setBoolValue(..., { fromUi: false }) call inside the existing useExecuteWhenChanged callback in Popover.tsx and a new equivalent hook in Expander.tsx. The fromUi: false flag correctly prevents an extra rerun while keeping the widget manager in sync with the backend's authoritative state.

Confidence Score: 5/5

Safe to merge — targeted fix with comprehensive unit and E2E test coverage, no regressions identified.

All findings are P2 or lower. The fix is minimal and well-scoped: it adds a single setBoolValue(…, { fromUi: false }) call in the render-time useExecuteWhenChanged callback for both Popover and Expander. The fromUi: false flag is the correct mechanism to sync state without triggering an extra rerun. Guards (widgetId check, notNullOrUndefined) mirror the pattern already used in Popover before this PR. Unit tests cover both expand and collapse directions; E2E tests reproduce the exact regression scenario from issue #14943.

No files require special attention.

Important Files Changed

Filename Overview
frontend/lib/src/components/elements/Popover/Popover.tsx Adds widgetMgr?.setBoolValue(…, { fromUi: false }) inside the existing useExecuteWhenChanged callback to sync the widget manager on backend-driven open-state changes; logic is guarded by widgetId and notNullOrUndefined checks.
frontend/lib/src/components/elements/Expander/Expander.tsx Adds a new useExecuteWhenChanged block (mirroring the Popover fix) that syncs the widget manager when element.expanded changes programmatically; properly guarded and uses fromUi: false to avoid triggering a rerun.
frontend/lib/src/components/elements/Popover/Popover.test.tsx Updates existing 'syncs open state' test to assert the new setBoolValue call, adds a new 'programmatic close' test; the previously-passing not.toHaveBeenCalled assertion is correctly replaced to reflect the new intended behaviour.
frontend/lib/src/components/elements/Expander/Expander.test.tsx Adds two new unit tests ('syncs widget manager state on programmatic expand/collapse') that directly assert the setBoolValue call arguments for both expand and collapse scenarios.
e2e_playwright/st_expander.py Adds two stateful expanders with programmatic-close buttons for the regression E2E test; straightforward fixture addition.
e2e_playwright/st_expander_test.py Adds test_programmatic_close_does_not_reopen_other_expander E2E test and bumps NUMBER_OF_EXPANDERS from 22 to 24 to account for the two new fixture expanders.
e2e_playwright/st_popover.py Adds two stateful popovers with programmatic-close buttons for the regression E2E test.
e2e_playwright/st_popover_test.py Adds test_programmatic_close_does_not_reopen_other_popover E2E test and bumps expected popover count from 25 to 27.

Sequence Diagram

sequenceDiagram
    participant User
    participant Frontend
    participant WidgetMgr as WidgetStateManager
    participant Backend

    User->>Frontend: Click "Close A" button
    Frontend->>WidgetMgr: setBoolValue(popoverA, false, fromUi:true)
    WidgetMgr->>Backend: sendRerunBackMsg (open=false)
    Backend->>Frontend: Re-render with element.open=false
    Frontend->>WidgetMgr: setBoolValue(popoverA, false, fromUi:false) NEW
    Note over WidgetMgr: Widget manager now has correct false value

    User->>Frontend: Click to open Popover B
    Frontend->>WidgetMgr: setBoolValue(popoverB, true, fromUi:true)
    WidgetMgr->>Backend: sendRerunBackMsg (popoverB=true, popoverA=false)
    Backend->>Frontend: Re-render (A stays closed, B opens)
Loading

Reviews (1): Last reviewed commit: "[fix] Sync widget manager state on progr..." | Re-trigger Greptile

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.

Pull request overview

Fixes a regression where Popover/Expander components that are programmatically closed (via st.session_state.<key> = False) could reopen on a later rerun because the frontend WidgetStateManager retained a stale true state. This aligns the frontend widget manager state with backend-driven open/expanded updates so subsequent reruns send the correct value back.

Changes:

  • Sync WidgetStateManager boolean state when backend programmatically updates Popover open state and Expander expanded state (using { fromUi: false } to avoid triggering reruns).
  • Add/adjust frontend unit tests to assert widget manager syncing for programmatic open/close and expand/collapse.
  • Add E2E regression tests covering multi-popover and multi-expander programmatic close scenarios; update expected element counts in existing E2E tests.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
frontend/lib/src/components/elements/Popover/Popover.tsx Sync widget manager bool state when backend changes element.open.
frontend/lib/src/components/elements/Popover/Popover.test.tsx Update/add tests to verify widget manager sync on programmatic open/close.
frontend/lib/src/components/elements/Expander/Expander.tsx Sync widget manager bool state when backend changes element.expanded.
frontend/lib/src/components/elements/Expander/Expander.test.tsx Add tests to verify widget manager sync on programmatic expand/collapse.
e2e_playwright/st_popover_test.py Add regression E2E test; update expected popover count.
e2e_playwright/st_popover.py Add multi-popover app scenario exercising programmatic close via session state.
e2e_playwright/st_expander_test.py Add regression E2E test; update expected expander count.
e2e_playwright/st_expander.py Add multi-expander app scenario exercising programmatic close via session state.

Comment thread frontend/lib/src/components/elements/Expander/Expander.test.tsx Outdated
@github-actions github-actions Bot removed the ai-review If applied to PR or issue will run AI review workflow label Apr 27, 2026

@github-actions github-actions Bot 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.

Summary

This PR fixes a state-sync regression (#14943) where programmatically closing a widget-mode popover or expander (e.g. st.session_state.key = False) would leave stale frontend widget state, causing the element to reopen when another stateful widget triggered a rerun. The fix updates the WidgetStateManager when the backend-controlled open/expanded value changes, using { fromUi: false } to avoid triggering extra reruns. Both unit tests and E2E regression tests are added for the popover and expander flows.

Reviewer agreement: Both available reviewers (gemini-3.1-pro and gpt-5.3-codex-high) agree the fix is logically correct, well-scoped, and backed by strong test coverage. They agree on backwards compatibility, security, accessibility, and external-test assessment (no risk). The sole disagreement is on implementation approach — see Code Quality.

Missing review: claude-4.6-opus-high-thinking failed to complete review.

Code Quality

Both reviewers confirm the root cause is correctly identified and the fix is sound: syncing widgetMgr state when the backend overrides open/expanded prevents stale values from being sent on subsequent reruns.

Point of disagreement: gemini-3.1-pro flags that calling widgetMgr.setBoolValue() inside useExecuteWhenChanged violates React's render purity rules, since WidgetStateManager is an external store. It recommends moving the sync to a useEffect. gpt-5.3-codex-high found no issues and considers the implementation clean and consistent with existing patterns.

Consolidation assessment: After reviewing the codebase, useExecuteWhenChanged is an established render-time hook used in 8+ components (Slider, Selectbox, BaseColorPicker, DeckGlJsonChart, Sidebar, AppView, etc.). Notably, Sidebar.tsx already calls an external callback (onToggleCollapse) during render via this same hook — so the pattern of triggering external side effects in useExecuteWhenChanged has existing precedent. The widgetMgr.setBoolValue() call with { fromUi: false } is effectively idempotent and does not trigger reruns, making the practical risk from React concurrent mode negligible. While gemini's observation about render purity is technically valid, it does not represent a novel anti-pattern in this codebase. Moving the sync to useEffect could also introduce a one-frame timing gap that might re-expose the stale-state bug in edge cases. This is noted as a non-blocking suggestion in the inline comments.

Test Coverage

Test coverage is excellent and directly targets the regression:

  • Unit tests: New tests in Expander.test.tsx and Popover.test.tsx verify that programmatic state changes (both open→close and close→open) update widgetMgr with { fromUi: false }. Tests include both positive and negative assertions (stale reopen prevention).
  • E2E tests: New Playwright regression tests in st_expander_test.py and st_popover_test.py reproduce the exact scenario from #14943 — programmatically closing one element, then interacting with another, and verifying the first stays closed.
  • Existing element count assertions are correctly updated to account for newly added test widgets (22→24 expanders, 25→27 popovers).

Backwards Compatibility

No breaking changes. The fix only corrects state synchronization behavior and does not alter any public APIs or expected component behaviors. Users will only observe corrected behavior in the previously broken scenario.

Security & Risk

No security-sensitive surfaces were modified. No changes to auth, cookies, routing, WebSocket transport, CSP/headers, file serving, external networking, eval/exec paths, or dependencies. Regression risk is low and mitigated by targeted unit and E2E tests.

External test recommendation

  • Recommend external_test: No
  • Triggered categories: None
  • Evidence:
    • frontend/lib/src/components/elements/Popover/Popover.tsx: local frontend widget-state sync fix only; no cross-origin, routing, auth, transport, storage, or embedding-boundary changes.
    • frontend/lib/src/components/elements/Expander/Expander.tsx: same class of frontend state-sync fix with { fromUi: false }; no external-host/runtime integration points changed.
  • Suggested external_test focus areas: N/A
  • Confidence: High
  • Assumptions and gaps: Assessment is based on this PR diff only; changes are strictly confined to frontend widget state management.

Accessibility

No accessibility impact. The changes only affect internal state synchronization and do not modify the DOM structure, ARIA attributes, focus behavior, or keyboard interactions.

Recommendations

  1. Non-blocking: Consider moving the widgetMgr.setBoolValue() call to a useEffect in both Expander.tsx and Popover.tsx to align with strict React render purity. This is a codebase-wide pattern question (other useExecuteWhenChanged callsites also trigger external side effects) and not specific to this PR. See inline comments for details.

Verdict

APPROVED: The fix correctly addresses the root cause of #14943 with a well-scoped, idempotent state sync and comprehensive test coverage. The render-purity concern is noted but non-blocking given established codebase patterns and negligible practical risk.


This is a consolidated AI review by claude-4.6-opus-high-thinking, synthesizing reviews from gemini-3.1-pro (CHANGES REQUESTED) and gpt-5.3-codex-high (APPROVED). claude-4.6-opus-high-thinking failed to complete individual review.

This review also includes 2 inline comment(s) on specific code lines.

// expanded value (e.g. st.session_state.key = False). Without this, the
// widget manager retains the stale value and sends it back on the next
// rerun, causing the expander to revert to its old state.
useExecuteWhenChanged(() => {

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.

thought: Calling widgetMgr.setBoolValue() during render (via useExecuteWhenChanged) technically violates React's render purity rules, since WidgetStateManager is an external store. The project's frontend/AGENTS.md guidelines state: "Use an Effect only to synchronize the component with an external system" — which implies external-system sync belongs in a useEffect. That said, this pattern has existing precedent in the codebase (e.g. Sidebar.tsx calls onToggleCollapse via useExecuteWhenChanged), and the call here is idempotent with { fromUi: false }, so the practical risk is negligible. Non-blocking, but worth considering as a broader codebase cleanup.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Acknowledged — intentionally keeping this in useExecuteWhenChanged rather than moving to useEffect for two reasons:

  1. Timing: splitting setOpen (render-time) and setBoolValue (useEffect) would create a window where the local state is updated but the widget manager is not. If another widget triggers a flush in that gap, the stale value gets sent to the backend — exactly the bug this PR fixes.
  2. Precedent: Sidebar.tsx already calls onToggleCollapse (an external side effect) through this same hook. The call here is idempotent and uses { fromUi: false } so it cannot trigger reruns or cascading renders.

Agree this is worth revisiting as a broader codebase cleanup if the project moves toward stricter render purity, but not in scope for this bug fix.

// on subsequent reruns. Without this, a programmatic close (e.g.
// st.session_state.key = False) would leave a stale "true" in the widget
// state, causing the popover to reopen when another widget triggers a rerun.
widgetMgr?.setBoolValue(

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.

thought: Same pattern as Expander — widgetMgr.setBoolValue() is called during render via useExecuteWhenChanged. The setOpen(element.open) part is appropriate for render-time state adjustment, but the widget manager mutation is an external side effect. If this is ever refactored, consider splitting: keep setOpen in useExecuteWhenChanged and move widgetMgr.setBoolValue() to a useEffect. Non-blocking given established codebase conventions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same rationale as the Expander comment — keeping both calls together in useExecuteWhenChanged avoids a timing gap where a concurrent flush could read stale widget state. The { fromUi: false } source ensures no rerun is triggered.

@github-actions github-actions Bot 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.

Summary

This PR fixes a state-sync bug (#14943) where programmatically closing a widget-mode popover or expander (e.g. st.session_state.key = False) would leave stale frontend widget state, causing the element to reopen when another stateful widget triggered a rerun. The fix adds a widgetMgr.setBoolValue(..., { fromUi: false }) call inside the existing useExecuteWhenChanged hook in both Popover.tsx and Expander.tsx, ensuring the widget manager stays in sync with backend-driven state changes without triggering additional reruns. Both unit tests and E2E regression tests are added.

Reviewer consensus: All three reviewers (claude-4.6-opus-high-thinking, gemini-3.1-pro, gpt-5.3-codex-high) agree the root-cause analysis is correct, the fix is well-scoped, test coverage is thorough, and there are no backwards compatibility, security, or accessibility concerns. The sole disagreement is on implementation approach — see Code Quality.

Code Quality

All reviewers confirm the root cause is correctly identified: the WidgetStateManager retained stale state when the backend overrode open/expanded, and syncing it with { fromUi: false } prevents stale values from being sent on subsequent reruns.

Point of disagreement — render purity: gemini-3.1-pro flags that calling widgetMgr.setBoolValue() inside useExecuteWhenChanged violates React's render purity rules and requests changes to move the sync to a useEffect. Both claude-4.6-opus-high-thinking and gpt-5.3-codex-high find the implementation clean and consistent with existing patterns, noting no issues.

Consolidation assessment: After verifying the codebase, useExecuteWhenChanged is an established render-time hook used in 8+ components (Slider, Selectbox, BaseColorPicker, DeckGlJsonChart, Sidebar, AppView, etc.). Notably, Sidebar.tsx already calls an external callback (onToggleCollapse) during render via this same hook — so triggering external side effects in useExecuteWhenChanged has existing precedent. The setBoolValue call with { fromUi: false } is effectively idempotent and does not trigger reruns, making the practical risk from React concurrent mode negligible. Additionally, moving the sync to useEffect could introduce a one-frame timing gap that might re-expose the stale-state bug in edge cases. While gemini's observation about render purity is technically valid, it does not represent a novel anti-pattern in this codebase and is assessed as non-blocking. See inline comments for details.

Test Coverage

Test coverage is excellent and directly targets the regression:

  • Frontend unit tests: New tests in Expander.test.tsx verify programmatic expand and collapse update widgetMgr with { fromUi: false }. Updated and new tests in Popover.test.tsx cover programmatic open and close with the same assertions. Tests include both positive and negative assertions (stale reopen prevention).
  • E2E tests: New Playwright regression tests in st_expander_test.py and st_popover_test.py reproduce the exact bug scenario from #14943 — programmatically close one element, interact with another, verify the first stays closed.
  • Existing element count assertions are correctly updated (22→24 expanders, 25→27 popovers).

Backwards Compatibility

No breaking changes. The fix only corrects state synchronization behavior for widget-mode popovers and expanders. Non-widget-mode and passively-keyed components are unaffected due to the !widgetId guard. Users will only observe corrected behavior in the previously broken scenario.

Security & Risk

No security-sensitive surfaces were modified. No changes to auth, cookies, routing, WebSocket transport, CSP/headers, file serving, external networking, eval/exec paths, or dependencies. Regression risk is low and mitigated by targeted unit and E2E tests.

External test recommendation

  • Recommend external_test: No
  • Triggered categories: None
  • Evidence:
    • frontend/lib/src/components/elements/Popover/Popover.tsx: Pure frontend widget state sync change — no routing, auth, embedding, cross-origin, or transport impact.
    • frontend/lib/src/components/elements/Expander/Expander.tsx: Same scope — widget manager sync during render with { fromUi: false }.
  • Suggested external_test focus areas: N/A
  • Confidence: High
  • Assumptions and gaps: None. Changes are strictly confined to React component render logic and widget state management, which behave identically in local and externally hosted contexts.

Accessibility

No accessibility impact. The changes are entirely in widget state management logic — no DOM structure, ARIA attributes, focus management, or keyboard interaction changes.

Recommendations

  1. Non-blocking: The render-purity concern about calling widgetMgr.setBoolValue() inside useExecuteWhenChanged is noted but assessed as non-blocking given established codebase patterns and negligible practical risk. This could be addressed as a broader codebase cleanup in a future PR. See inline comments for details.
  2. Non-blocking: The two new Expander widget-sync tests are placed inside the describe("passive state persistence", ...) block but test widget-mode behavior. They would be more logically grouped under the existing describe("widget mode (widgetMgr + element.id)", ...) block for consistency with Popover.test.tsx.

Verdict

APPROVED: Well-targeted bug fix with correct root-cause analysis, consistent implementation across Popover and Expander, thorough unit and E2E test coverage, and no backwards compatibility or security concerns. The render-purity observation is non-blocking given established codebase conventions.


This is a consolidated AI review by claude-4.6-opus-high-thinking, synthesizing reviews from claude-4.6-opus-high-thinking (APPROVED), gemini-3.1-pro (CHANGES REQUESTED), and gpt-5.3-codex-high (APPROVED).

This review also includes 3 inline comment(s) on specific code lines.

Comment thread frontend/lib/src/components/elements/Expander/Expander.tsx
Comment thread frontend/lib/src/components/elements/Popover/Popover.tsx
Comment thread frontend/lib/src/components/elements/Expander/Expander.test.tsx Outdated
Address review feedback: the two new Expander unit tests for
programmatic state sync belong in "widget mode" not "passive state
persistence".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
@kmcgrady kmcgrady changed the title Fix programmatically closed popovers/expanders reopening on interaction with another [fix] Programmatically closed popovers/expanders reopening on interaction with another May 1, 2026
@sfc-gh-lwilby-1 sfc-gh-lwilby-1 self-assigned this May 11, 2026
@sfc-gh-lwilby-1 sfc-gh-lwilby-1 merged commit 3191baf into develop May 11, 2026
41 checks passed
@sfc-gh-lwilby-1 sfc-gh-lwilby-1 deleted the fix/popover-expander-programmatic-close-stale-state branch May 11, 2026 15:50
joanaarnauth pushed a commit to joanaarnauth/streamlit that referenced this pull request May 17, 2026
…tion with another (streamlit#14945)

## Summary

- Fixes streamlit#14943 — programmatically closed popovers reopen when
interacting with another stateful popover
- When `st.session_state.key = False` closes a popover/expander, the
frontend's `WidgetStateManager` was not updated, leaving a stale `true`
value that got sent back to the backend on the next rerun
- Added `widgetMgr.setBoolValue(..., { fromUi: false })` to sync the
widget manager when the backend overrides the open/expanded state,
without triggering an additional rerun
- Applied the same fix to `st.expander` which had the identical latent
bug

## Test plan

- [x] Updated Popover unit test ("syncs open state when element.open
changes programmatically") to verify widget manager sync
- [x] Added Popover unit test ("syncs widget manager state on
programmatic close to prevent stale reopens")
- [x] Added Expander unit test ("syncs widget manager state on
programmatic expand change")
- [x] Added Expander unit test ("syncs widget manager state on
programmatic collapse to prevent stale reopens")
- [x] Added Popover E2E test
(`test_programmatic_close_does_not_reopen_other_popover`)
- [x] Added Expander E2E test
(`test_programmatic_close_does_not_reopen_other_expander`)
- [x] All existing Popover/Expander unit tests pass (49/49)
- [x] Both new E2E tests pass
- [x] Verified manually via Playwright against `make debug` that the fix
resolves the reported issue

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Made with [Orca](https://github.com/stablyai/orca) 🐋

---------

Co-authored-by: Orca <help@stably.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:bugfix PR contains bug fix implementation impact:users PR changes affect end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Programmatically closed popovers reopen when interacting with another stateful popover

4 participants