fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(ui): close only the open Select on Escape inside a Drawer - #9176

Merged
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer
Jul 16, 2026
Merged

fix(ui): close only the open Select on Escape inside a Drawer#9176
alexcarpenter merged 2 commits into
mainfrom
esc-closes-checkout-drawer

Conversation

@alexcarpenter

@alexcarpenteralexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Pressing Escape while a Select was open inside a Drawer (for example the payment method picker in Checkout) dismissed the entire Drawer instead of just the Select. Two issues were at play: the Select never applied floating-ui's getFloatingProps() to its floating element, so its Escape handler only lived as a native document listener that the Drawer's synthetic stopPropagation() prevented from firing; and Drawer.Root was not a FloatingTree node, so nested floating elements were not recognized as its children. The Select now wires up its interaction props (handling Escape itself and stopping propagation) and the Drawer roots a floating tree, so Escape now closes only the open Select and a second Escape closes the Drawer. To test: open the Checkout drawer, open the payment method Select, press Escape, and confirm only the Select closes.

BEFORE

before.mov

AFTER

after.mov

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Bug Fixes

    • Pressing Escape while a Select menu is open inside a Drawer now closes only the Select menu.
    • Pressing Escape again dismisses the Drawer as expected.
    • Improved keyboard interaction for nested floating components and drawers.
  • Tests

    • Added coverage verifying Select and Drawer dismissal behavior.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1531723

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
NameType
@clerk/uiPatch
@clerk/chrome-extensionPatch
@clerk/swingsetPatch

Not sure what this means? Click here to learn what changesets are.

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

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJul 16, 2026 3:39pm
swingsetReadyReadyPreview, CommentJul 16, 2026 3:39pm

Request Review

@coderabbitai

coderabbitaiBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 646a7a4d-034f-4db2-9be5-c09e9d70f567

📥 Commits

Reviewing files that changed from the base of the PR and between de00526 and 1531723.

📒 Files selected for processing (1)
  • packages/ui/src/elements/__tests__/Drawer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/elements/tests/Drawer.test.tsx

📝 Walkthrough

Walkthrough

Updates Floating UI nesting so Escape closes a Select inside a Drawer without dismissing the Drawer, with an integration test and changeset documenting the fix.

Changes

Drawer Select Escape handling

Layer / File(s)Summary
Root Drawer in the floating tree
packages/ui/src/elements/Drawer.tsx
Drawer roots create or join a FloatingTree, register a node, and wrap drawer content in FloatingNode.
Scope Select Escape handling
packages/ui/src/elements/Select.tsx, packages/ui/src/elements/__tests__/Drawer.test.tsx, .changeset/drawer-select-escape.md
Select options apply floating interaction props, and the test verifies Escape closes the Select without dismissing the Drawer; the changeset records the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny in a Drawer wide,
I tap Escape—my Select slips aside.
The Drawer stays still,
As floating trees will,
And carrots remain safely inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and accurately summarizes the main change: Escape now closes only the Select inside a Drawer.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-newBot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9176

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9176

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9176

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9176

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9176

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9176

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9176

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9176

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9176

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9176

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9176

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9176

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9176

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9176

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9176

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9176

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9176

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9176

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9176

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9176

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9176

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9176

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9176

commit: 1531723

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T15:39:50.210Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 1531723.

@coderabbitaicoderabbitaiBot 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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/elements/Drawer.tsx (1)

112-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the floating tree node ID in sync.

floatingProps.nodeId can override the generated ID passed to useFloating, but FloatingNode still uses the original ID. That splits tree registration and can break nested dismiss/focus behavior. Omit nodeId from floatingProps, or derive one effective ID and use it for both.

🤖 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/ui/src/elements/Drawer.tsx` around lines 112 - 121, Update the
Drawer component’s useFloating/FloatingNode setup to use one effective node ID:
prevent floatingProps.nodeId from overriding the generated nodeId, or derive the
override-aware ID and pass that same value to both useFloating and FloatingNode.
Preserve the existing nested dismiss and focus behavior.

Source: Path instructions

🤖 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 `@packages/ui/src/elements/__tests__/Drawer.test.tsx`:
- Around line 61-64: Extend the Escape-key test around the nested Select and
Drawer behavior by triggering a second Escape after confirming the Select is
dismissed, then assert that onOpenChange is called with false. Keep the existing
assertion that the first Escape does not dismiss the Drawer.
- Around line 19-20: Replace the as any casts in the
ClerkInstanceContext.Provider and EnvironmentProvider fixtures within
Drawer.test.tsx with properly typed Clerk and environment mocks. Ensure both
provider values satisfy their respective context types while preserving the
existing test data and exposing future provider shape changes to TypeScript.
---
Outside diff comments:
In `@packages/ui/src/elements/Drawer.tsx`:
- Around line 112-121: Update the Drawer component’s useFloating/FloatingNode
setup to use one effective node ID: prevent floatingProps.nodeId from overriding
the generated nodeId, or derive the override-aware ID and pass that same value
to both useFloating and FloatingNode. Preserve the existing nested dismiss and
focus behavior.
🪄 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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce80d4d-4e47-4a06-97a4-a275a4c5e08f

📥 Commits

Reviewing files that changed from the base of the PR and between bcbdda6 and de00526.

📒 Files selected for processing (4)
  • .changeset/drawer-select-escape.md
  • packages/ui/src/elements/Drawer.tsx
  • packages/ui/src/elements/Select.tsx
  • packages/ui/src/elements/__tests__/Drawer.test.tsx

Comment on lines +19 to +20
<ClerkInstanceContext.Provider value={{ value: { client: {}, user: {} } as any }}>
<EnvironmentProvider value={{ displayConfig: { applicationName: 'TestApp' } } as any}>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Drawer.test.tsx ==\n'
cat -n packages/ui/src/elements/__tests__/Drawer.test.tsx
printf'\n== Search ClerkInstanceContext / EnvironmentProvider definitions ==\n'
rg -n "ClerkInstanceContext|EnvironmentProvider|displayConfig|applicationName|value: \{\s*client" packages/ui/src packages -g '!**/dist/**' -g '!**/build/**'printf'\n== Type outlines for likely provider files ==\n'
fd -a "ClerkInstanceContext" packages/ui/src packages ||true
fd -a "EnvironmentProvider" packages/ui/src packages ||true

Repository: clerk/javascript

Length of output: 50373


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== packages/ui/src/contexts/EnvironmentContext.tsx ==\n'
cat -n packages/ui/src/contexts/EnvironmentContext.tsx
printf'\n== packages/ui/src/test/create-fixtures.tsx (relevant slice) ==\n'
sed -n '1,220p' packages/ui/src/test/create-fixtures.tsx
printf'\n== Search for reusable clerk/environment test fixtures in packages/ui ==\n'
rg -n "create-fixtures|environmentMock|ClerkInstanceContext.Provider|EnvironmentProvider value=" packages/ui/src -g '!**/dist/**' -g '!**/build/**'

Repository: clerk/javascript

Length of output: 20221


Use typed fixtures for these providers. Replace the as any casts with a typed Clerk/environment mock so ClerkInstanceContext and EnvironmentProvider shape changes surface here instead of being hidden by the test setup.

🤖 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/ui/src/elements/__tests__/Drawer.test.tsx` around lines 19 - 20,
Replace the as any casts in the ClerkInstanceContext.Provider and
EnvironmentProvider fixtures within Drawer.test.tsx with properly typed Clerk
and environment mocks. Ensure both provider values satisfy their respective
context types while preserving the existing test data and exposing future
provider shape changes to TypeScript.

Source: Coding guidelines

Comment threadpackages/ui/src/elements/__tests__/Drawer.test.tsx
@alexcarpenter
alexcarpenter merged commit 2632d88 into mainJul 16, 2026
53 checks passed
@alexcarpenter
alexcarpenter deleted the esc-closes-checkout-drawer branch July 16, 2026 16:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexcarpenter@maxyinger