Skip to content

Conversation

@wobsoriano
Copy link
Member

@wobsoriano wobsoriano commented Feb 12, 2026

Description

Migrate #7798 to Core 3

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

  • Improvements

    • Enhanced keyless prompt animations and content presentation for improved user experience.
    • Refined interaction patterns during the keyless authentication workflow.
    • Better visual feedback for toggling and expanding keyless-related UI elements.
  • Testing

    • Strengthened test infrastructure for more reliable validation of keyless functionality.

@vercel
Copy link

vercel bot commented Feb 12, 2026

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Feb 12, 2026 10:06pm

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Feb 12, 2026

🦋 Changeset detected

Latest commit: e2ebca3

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

This PR includes changesets to release 3 packages
Name Type
@clerk/ui Patch
@clerk/testing Patch
@clerk/chrome-extension Patch

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

This pull request updates the KeylessPrompt component and related testing infrastructure. The changes include a structural refactor of the KeylessPrompt component introducing a state machine pattern with new types (STATES) and utility functions (getCurrentState, getResolvedContent). The component rendering logic is replaced with a declarative, state-driven approach. The test page object for the keyless popover is updated to use role-based selectors instead of direct DOM queries. A new comprehensive test suite is added covering multiple state combinations and component behaviors. Test fixtures are expanded with a withClaimedAt helper, and integration tests are simplified by removing redundant assertions.

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: a refactor of the Keyless UI component with structural improvements to state management and rendering logic.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


No actionable comments were generated in the recent review. 🎉


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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 12, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7834

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7834

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

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

@clerk/upgrade

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

@clerk/vue

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

commit: e2ebca3

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/ui/src/components/devPrompts/KeylessPrompt/index.tsx`:
- Around line 296-303: The memoized claimUrlToDashboard in KeylessPrompt reads
window.location.href during render which breaks SSR; modify the useMemo to guard
access to window by checking typeof window !== 'undefined' (or the same guard
used elsewhere in this codebase) before appending return_url, and fallback to a
safe value (e.g., props.claimUrl or props.copyKeysUrl) when window is
unavailable; update the logic around claimUrlToDashboard, useMemo,
props.claimUrl and props.copyKeysUrl to only reference window.location.href on
the client.

Comment on lines 296 to +303
const claimUrlToDashboard = useMemo(() => {
if (claimed) {
return _props.copyKeysUrl;
return props.copyKeysUrl;
}

const url = new URL(_props.claimUrl);
// Clerk Dashboard accepts a `return_url` query param when visiting `/apps/claim`.
const url = new URL(props.claimUrl);
url.searchParams.append('return_url', window.location.href);
return url.href;
}, [claimed, _props.copyKeysUrl, _props.claimUrl]);
}, [claimed, props.copyKeysUrl, props.claimUrl]);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for KeylessPrompt imports and usage across the codebase
rg -nP --type=tsx --type=ts 'KeylessPrompt\b' --max-count=50

Repository: clerk/javascript

Length of output: 87


🏁 Script executed:

# Check if the file has any 'use client' directive or SSR markers
cat -n packages/ui/src/components/devPrompts/KeylessPrompt/index.tsx | head -20

Repository: clerk/javascript

Length of output: 894


🏁 Script executed:

# Look for SSR-related patterns in the codebase
rg -nP --type=tsx --type=ts "typeof window|'use client'|SSR" packages/ui/src --max-count=30

Repository: clerk/javascript

Length of output: 87


🏁 Script executed:

# Search for KeylessPrompt without type specification
rg 'KeylessPrompt' -n --max-count=30

Repository: clerk/javascript

Length of output: 2419


🏁 Script executed:

# Check if file has 'use client' directive anywhere
grep -n "'use client'" packages/ui/src/components/devPrompts/KeylessPrompt/index.tsx

Repository: clerk/javascript

Length of output: 42


🏁 Script executed:

# Get full file to understand context
wc -l packages/ui/src/components/devPrompts/KeylessPrompt/index.tsx

Repository: clerk/javascript

Length of output: 125


🏁 Script executed:

# Check the export wrapper of KeylessPrompt (around line 570)
sed -n '565,576p' packages/ui/src/components/devPrompts/KeylessPrompt/index.tsx

Repository: clerk/javascript

Length of output: 268


🏁 Script executed:

# Check the Components.tsx file where KeylessPrompt is used (around line 709)
sed -n '700,720p' packages/ui/src/Components.tsx

Repository: clerk/javascript

Length of output: 1059


🏁 Script executed:

# Check if the parent UI component or Components.tsx has 'use client'
head -30 packages/ui/src/Components.tsx

Repository: clerk/javascript

Length of output: 1208


🏁 Script executed:

# Check the broader context of lazyModules setup
head -30 packages/ui/src/lazyModules/components.ts

Repository: clerk/javascript

Length of output: 2610


🏁 Script executed:

# Check if Components.tsx has 'use client' directive anywhere in the file
grep -n "use client" packages/ui/src/Components.tsx

Repository: clerk/javascript

Length of output: 42


🏁 Script executed:

# Check the package.json for UI package to understand SSR intent
cat packages/ui/package.json | head -50

Repository: clerk/javascript

Length of output: 1494


🏁 Script executed:

# Look at the problematic line context more closely (lines 290-310)
sed -n '290,310p' packages/ui/src/components/devPrompts/KeylessPrompt/index.tsx

Repository: clerk/javascript

Length of output: 929


🏁 Script executed:

# Search for other SSR guards in the codebase (typeof window checks)
rg "typeof window" packages/ui/src --max-count=20

Repository: clerk/javascript

Length of output: 927


Add SSR guard before accessing window.location.href to prevent server-side crashes.

Lines 296-303 access window.location.href during render in a useMemo. The @clerk/ui package explicitly declares "react-server" export support and KeylessPrompt is rendered from Components.tsx without a 'use client' directive, meaning it can execute on the server. This will crash during SSR. Add the guard pattern used elsewhere in the codebase:

   const claimUrlToDashboard = useMemo(() => {
     if (claimed) {
       return props.copyKeysUrl;
     }
     const url = new URL(props.claimUrl);
-    url.searchParams.append('return_url', window.location.href);
+    if (typeof window !== 'undefined') {
+      url.searchParams.append('return_url', window.location.href);
+    }
     return url.href;
   }, [claimed, props.copyKeysUrl, props.claimUrl]);
🤖 Prompt for AI Agents
In `@packages/ui/src/components/devPrompts/KeylessPrompt/index.tsx` around lines
296 - 303, The memoized claimUrlToDashboard in KeylessPrompt reads
window.location.href during render which breaks SSR; modify the useMemo to guard
access to window by checking typeof window !== 'undefined' (or the same guard
used elsewhere in this codebase) before appending return_url, and fallback to a
safe value (e.g., props.claimUrl or props.copyKeysUrl) when window is
unavailable; update the logic around claimUrlToDashboard, useMemo,
props.claimUrl and props.copyKeysUrl to only reference window.location.href on
the client.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants