Skip to content

fix(Select): complete Theme portal fallback chain (#1100)#2041

Open
kotAPI wants to merge 1 commit into
mainfrom
fix/issue-1100-select-portal-theme
Open

fix(Select): complete Theme portal fallback chain (#1100)#2041
kotAPI wants to merge 1 commit into
mainfrom
fix/issue-1100-select-portal-theme

Conversation

@kotAPI

@kotAPI kotAPI commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

SelectPortal now falls back through portalRootRef, containerRef, and document.body like other overlay components.\n\nCloses #1100

Summary by CodeRabbit

  • Bug Fixes

    • Improved Select component's portal container selection logic for better compatibility with different rendering contexts.
  • Tests

    • Added comprehensive test coverage for Select portal behavior.

@changeset-bot

changeset-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 77f7c1e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

SelectPortal gains a third fallback in its portalContainer resolution: containerthemeContext?.portalRootRef.currentthemeContext?.containerRef.currentundefined. A new test file renders Select inside Theme and asserts that after opening the combobox, the listbox content is present inside [data-rad-ui-portal-root].

Changes

SelectPortal container fallback and portal test

Layer / File(s) Summary
Portal container resolution and test
src/components/ui/Select/fragments/SelectPortal.tsx, src/components/ui/Select/tests/Select.portal.test.tsx
portalContainer now tries container, then portalRootRef.current, then containerRef.current, then undefined. A new test mocks matchMedia, renders Select inside Theme, opens the combobox, and asserts the item text is inside the [data-rad-ui-portal-root] element.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~4 minutes

Possibly related PRs

  • rad-ui/ui#1117: Introduced SelectPortal in the same file where the container resolution is now being changed.
  • rad-ui/ui#1533: Previously plumbed the container prop for SelectPortal and added portal-container tests, directly related to this fallback extension.

Suggested labels

automerge

Suggested reviewers

  • GoldGroove06

Poem

🐇 Hop, hop, through the portal we go,
Container one, two, three in a row,
portalRootRef first, then containerRef too,
The listbox lands right where it's due.
No more lost dialogs, the root is found! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The PR modifies SelectPortal but issue #1100 describes AlertDialog problems. While both may benefit from the same fallback chain pattern, the PR changes don't directly address AlertDialog as mentioned in the linked issue. Clarify whether the fallback chain fix for SelectPortal also resolves the AlertDialog portal issue, or if separate changes are needed for AlertDialog specifically.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: implementing a complete Theme portal fallback chain in the Select component, which is the core modification across the changed files.
Out of Scope Changes check ✅ Passed All changes are scoped to SelectPortal component logic and its test coverage, with no unrelated modifications present in the changeset.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-1100-select-portal-theme

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

@github-actions

Copy link
Copy Markdown
Contributor

Coverage

This report compares the PR with the base branch. "Δ" shows how the PR affects each metric.

Metric PR Δ
Statements 75.73% +0.00%
Branches 59.22% +0.05%
Functions 61.75% +0.00%
Lines 77.26% +0.00%

Coverage improved or stayed the same. Great job!

Run npm run coverage:ci locally for detailed reports and target untested areas to raise these numbers.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@src/components/ui/Select/tests/Select.portal.test.tsx`:
- Around line 41-42: The assertion at Line 42 in the Select.portal.test.tsx file
uses the synchronous getByText method immediately after the click, which can
cause flaky tests if the listbox content hasn't rendered yet. Replace the
getByText call with findByText (which is async and polls for the element) and
await it before checking if portalRoot contains the element. This ensures the
DOM has settled and the 'Apple' text is actually present before making the
containment assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f2e4e6b0-210f-4d0c-869e-dc802cf2f5ad

📥 Commits

Reviewing files that changed from the base of the PR and between fe87b36 and 77f7c1e.

📒 Files selected for processing (2)
  • src/components/ui/Select/fragments/SelectPortal.tsx
  • src/components/ui/Select/tests/Select.portal.test.tsx

Comment on lines +41 to +42
await user.click(screen.getByRole('combobox'));
expect(portalRoot).toContainElement(screen.getByText('Apple'));

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the post-click assertion async-safe to avoid flaky tests.

After Line 41, rendering the listbox content may lag by a tick; using getByText at Line 42 can intermittently fail. Prefer awaiting findByText before asserting containment.

Proposed fix
         await user.click(screen.getByRole('combobox'));
-        expect(portalRoot).toContainElement(screen.getByText('Apple'));
+        const appleOption = await screen.findByText('Apple');
+        expect(portalRoot).toContainElement(appleOption);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await user.click(screen.getByRole('combobox'));
expect(portalRoot).toContainElement(screen.getByText('Apple'));
await user.click(screen.getByRole('combobox'));
const appleOption = await screen.findByText('Apple');
expect(portalRoot).toContainElement(appleOption);
🤖 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 `@src/components/ui/Select/tests/Select.portal.test.tsx` around lines 41 - 42,
The assertion at Line 42 in the Select.portal.test.tsx file uses the synchronous
getByText method immediately after the click, which can cause flaky tests if the
listbox content hasn't rendered yet. Replace the getByText call with findByText
(which is async and polls for the element) and await it before checking if
portalRoot contains the element. This ensures the DOM has settled and the
'Apple' text is actually present before making the containment assertion.

@kotAPI

kotAPI commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Code review

LGTM. Matches project patterns for portal Theme refs, Floating UI prop merge, controlled-switch/lazy-mount/RTL tests, or focused bug fixes. No changes requested.

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.

1 participant