Skip to content

feat(ui): Add dev-mode test credential hint to sign-in/sign-up fields#9162

Open
alexcarpenter wants to merge 2 commits into
mainfrom
dev-mode-test-email-tooltip
Open

feat(ui): Add dev-mode test credential hint to sign-in/sign-up fields#9162
alexcarpenter wants to merge 2 commits into
mainfrom
dev-mode-test-email-tooltip

Conversation

@alexcarpenter

@alexcarpenter alexcarpenter commented Jul 14, 2026

Copy link
Copy Markdown
Member

Description

Adds dev mode hints for prefilling email/phone number inputs with testing values.

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

  • New Features
    • Added dev-only info hints for sign-in and sign-up email/phone fields, with an ℹ️ popover and “insert test” quick actions.
    • Introduced a new warning button color scheme.
  • Bug Fixes
    • Improved phone input behavior so externally provided values update reliably after mount.
  • Developer Experience
    • Dev hints appear only in development mode and only for empty/non-test values.
  • Tests
    • Added unit tests for test-email conversion and test-phone detection helpers.

In development, the email/phone fields on sign-in and sign-up now reveal an info hint on hover/focus that nudges developers toward Clerk test credentials and can insert a suggested test email or phone number.
@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2dadf50

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/chrome-extension Patch
@clerk/swingset 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

@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jul 14, 2026 9:17pm
swingset Ready Ready Preview, Comment Jul 14, 2026 9:17pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Development-only test credential hints are added to sign-in and sign-up email or phone fields. The hint displays guidance, verification information, and insertion actions, while phone inputs synchronize externally inserted values.

Changes

Development credential hints

Layer / File(s) Summary
Hint component and interaction
packages/ui/src/elements/FieldDevHint.tsx, packages/ui/src/primitives/Button.tsx
Adds an accessible development-only popover with optional credential insertion actions and warning button styling.
Field label and input wiring
packages/ui/src/elements/FieldControl.tsx, packages/ui/src/elements/Form.tsx
Passes devHint through common inputs and renders the hint beside labels with hover/focus visibility behavior.
Authentication form integration
packages/ui/src/components/SignIn/SignInStart.tsx, packages/ui/src/components/SignUp/SignUpForm.tsx, packages/ui/src/elements/PhoneInput/index.tsx, packages/ui/src/utils/*, .changeset/dev-mode-test-credential-hint.md
Adds test email and phone conversion, detection, and insertion actions; synchronizes inserted phone values; tests the helper utilities; and records the UI patch release.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Developer
  participant FieldDevHint
  participant SignInStart
  participant SignUpForm
  participant PhoneInputBase
  Developer->>FieldDevHint: Focus or open an empty field hint
  FieldDevHint->>Developer: Show test credential guidance
  Developer->>FieldDevHint: Select insertion action
  FieldDevHint->>SignInStart: Set test identifier
  FieldDevHint->>SignUpForm: Set test email or phone
  SignUpForm->>PhoneInputBase: Pass updated phone value
  PhoneInputBase->>PhoneInputBase: Synchronize internal phone state
Loading

Poem

I’m a bunny with a hint by the field,
Test credentials are neatly revealed.
Tap the button, hop values right in,
A tiny code helps testing begin.
In dev mode, the carrot lights glow!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a development-mode test credential hint for sign-in and sign-up fields.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check 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.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-14T21:18:41.665Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 0
🔴 Breaking changes 0
🟡 Non-breaking changes 0
🟢 Additions 0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 2dadf50.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/components/SignIn/SignInStart.tsx`:
- Around line 574-592: Extract the shared email and phone dev-hint factories
into a reusable utility, preserving the existing copy, labels, and test values.
In packages/ui/src/components/SignIn/SignInStart.tsx lines 574-592, replace the
inline ternary objects with createEmailTestHint/setValue or
createPhoneTestHint/setValue calls; in
packages/ui/src/components/SignUp/SignUpForm.tsx lines 89-95 and 107-113,
replace each corresponding inline object with the same shared helper and import
it.

In `@packages/ui/src/primitives/Button.tsx`:
- Around line 78-84: Update Button’s colorScheme type declaration to include the
warning literal alongside primary, secondary, neutral, and danger, making the
existing warning variant in the color scheme mapping accessible through the
typed API.
🪄 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: 5d1cdc48-72b8-4837-8c07-956abd3e5b88

📥 Commits

Reviewing files that changed from the base of the PR and between 99ac79f and fc45999.

📒 Files selected for processing (8)
  • .changeset/dev-mode-test-credential-hint.md
  • packages/ui/src/components/SignIn/SignInStart.tsx
  • packages/ui/src/components/SignUp/SignUpForm.tsx
  • packages/ui/src/elements/FieldControl.tsx
  • packages/ui/src/elements/FieldDevHint.tsx
  • packages/ui/src/elements/Form.tsx
  • packages/ui/src/elements/PhoneInput/index.tsx
  • packages/ui/src/primitives/Button.tsx

Comment on lines +574 to +592
const identifierDevHint =
identifierAttribute === 'phone_number'
? {
text: 'Testing? Use a test phone number so you skip a real SMS. Verify it on the next screen with the code 424242.',
action: {
label: 'Insert test phone number',
onInsert: () => identifierField.setValue('+12015550100'),
},
}
: identifierAttribute === 'email_address' || identifierAttribute === 'email_address_username'
? {
text: 'Testing? Use a test email so you skip a real inbox. Verify it on the next screen with the code 424242.',
action: {
label: 'Insert test email',
onInsert: () => identifierField.setValue('your_email+clerk_test@example.com'),
},
}
: undefined;

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 | 🟠 Major | ⚡ Quick win

Extract a shared factory for the dev-hint copy/actions to avoid triplicated literals.

The same hint text and test-credential values are hardcoded in three places across two files. Any future wording tweak or test-value change now needs three synchronized edits.

  • packages/ui/src/components/SignIn/SignInStart.tsx#L574-L592: replace the inline ternary literals with calls to a shared createEmailTestHint(setValue) / createPhoneTestHint(setValue) helper.
  • packages/ui/src/components/SignUp/SignUpForm.tsx#L89-L95: use the same shared email hint helper instead of the inline object.
  • packages/ui/src/components/SignUp/SignUpForm.tsx#L107-L113: use the same shared phone hint helper instead of the inline object.
♻️ Example shared helper
// e.g. packages/ui/src/utils/devHints.ts
export const createEmailTestHint = (setValue: (v: string) => void): FieldDevHintValue => ({
  text: 'Testing? Use a test email so you skip a real inbox. Verify it on the next screen with the code 424242.',
  action: { label: 'Insert test email', onInsert: () => setValue('your_email+clerk_test@example.com') },
});

export const createPhoneTestHint = (setValue: (v: string) => void): FieldDevHintValue => ({
  text: 'Testing? Use a test phone number so you skip a real SMS. Verify it on the next screen with the code 424242.',
  action: { label: 'Insert test phone number', onInsert: () => setValue('+12015550100') },
});
📍 Affects 2 files
  • packages/ui/src/components/SignIn/SignInStart.tsx#L574-L592 (this comment)
  • packages/ui/src/components/SignUp/SignUpForm.tsx#L89-L95
  • packages/ui/src/components/SignUp/SignUpForm.tsx#L107-L113
🤖 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/components/SignIn/SignInStart.tsx` around lines 574 - 592,
Extract the shared email and phone dev-hint factories into a reusable utility,
preserving the existing copy, labels, and test values. In
packages/ui/src/components/SignIn/SignInStart.tsx lines 574-592, replace the
inline ternary objects with createEmailTestHint/setValue or
createPhoneTestHint/setValue calls; in
packages/ui/src/components/SignUp/SignUpForm.tsx lines 89-95 and 107-113,
replace each corresponding inline object with the same shared helper and import
it.

Comment on lines +78 to +84
warning: {
[vars.accent]: theme.colors.$warning500,
[vars.accentHover]: theme.colors.$warning600,
[vars.accentContrast]: theme.colors.$white,
[vars.border]: theme.colors.$warning500,
[vars.alpha]: theme.colors.$warningAlpha50,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether 'warning' is added to the colorScheme prop type
rg -n "colorScheme" packages/ui/src/primitives/Button.tsx

Repository: clerk/javascript

Length of output: 426


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Button.tsx colorScheme references =="
rg -n "colorScheme" packages/ui/src/primitives/Button.tsx

echo
echo "== Repository-wide 'colorScheme: warning' references =="
rg -n "colorScheme\\s*[:=]\\s*'warning'|colorScheme\\s*=\\s*\\{?\\s*'warning'|colorScheme=\\\"warning\\\"|colorScheme='warning'" packages/ui/src

echo
echo "== Button component usages passing warning =="
rg -n "<Button[^>]*colorScheme=\\{?'warning'|<Button[^>]*colorScheme=\\\"warning\\\"" packages/ui/src

Repository: clerk/javascript

Length of output: 777


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Button.tsx colorScheme references =="
rg -n "colorScheme" packages/ui/src/primitives/Button.tsx

echo
echo "== Repository-wide Button colorScheme='warning' usages =="
rg -n "colorScheme=['\"]warning['\"]" packages/ui/src

echo
echo "== Repository-wide Button JSX warning usages =="
rg -n "<Button[^>]*colorScheme=[^>]*warning" packages/ui/src

echo
echo "== Repository-wide widened colorScheme unions =="
rg -n "colorScheme\\?:[^\\n]*warning|colorScheme[^\\n]*\\|[^\\n]*warning" packages/ui/src

Repository: clerk/javascript

Length of output: 1632


Add warning to Button's colorScheme union. The new variant entry is unreachable through the typed API until colorScheme?: 'primary' | 'secondary' | 'neutral' | 'danger' | 'warning' is updated.

🤖 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/primitives/Button.tsx` around lines 78 - 84, Update Button’s
colorScheme type declaration to include the warning literal alongside primary,
secondary, neutral, and danger, making the existing warning variant in the color
scheme mapping accessible through the typed API.

@pkg-pr-new

pkg-pr-new Bot commented Jul 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/electron

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

@clerk/electron-passkeys

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

@clerk/eslint-plugin

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

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

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

@clerk/upgrade

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

@clerk/vue

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

commit: 2dadf50

…ed email

The dev-mode test-credential hint now stays visible (as a warning) while the email/phone field holds a non-test value, and hides once it is a test credential. Inserting a test email transforms the currently typed address by adding the +clerk_test subaddress instead of replacing it.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/utils/clerkTestEmail.ts`:
- Around line 14-16: Update the Clerk test email detection around the existing
trimmed-email check to match clerk_test only as an exact subaddress segment in
the local part, excluding near-matches in segments or domains. Align the SignIn
and SignUp consumers’ checks with this exact matching behavior, and add
regression tests covering alex+clerk_testing@example.com and
alex@clerk_test.example.com.

In `@packages/ui/src/utils/clerkTestPhoneNumber.ts`:
- Around line 5-6: The isClerkTestPhoneNumber function currently matches only
the suffix, allowing incomplete or overlong values. Validate the normalized
phone number as exactly 10 digits or 11 digits prefixed with 1 before applying
the 55501xx test-number pattern, and add regression tests covering short and
overlong inputs.
🪄 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: adc68cb1-4137-49a9-8242-aa407e7bedb1

📥 Commits

Reviewing files that changed from the base of the PR and between fc45999 and 2dadf50.

📒 Files selected for processing (7)
  • packages/ui/src/components/SignIn/SignInStart.tsx
  • packages/ui/src/components/SignUp/SignUpForm.tsx
  • packages/ui/src/elements/FieldDevHint.tsx
  • packages/ui/src/utils/__tests__/clerkTestEmail.test.ts
  • packages/ui/src/utils/__tests__/clerkTestPhoneNumber.test.ts
  • packages/ui/src/utils/clerkTestEmail.ts
  • packages/ui/src/utils/clerkTestPhoneNumber.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/ui/src/elements/FieldDevHint.tsx
  • packages/ui/src/components/SignUp/SignUpForm.tsx
  • packages/ui/src/components/SignIn/SignInStart.tsx

Comment on lines +14 to +16
if (trimmed.includes(CLERK_TEST_SUBADDRESS)) {
return trimmed;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Match clerk_test as an exact subaddress segment.

includes treats values such as alex+clerk_testing@example.com or alex@clerk_test.example.com as test credentials. The SignIn and SignUp consumers also use broad value.includes('+clerk_test') checks, so the hint is hidden for non-test values. Match the local-part segment exactly and add regression tests for near-miss values.

Proposed fix
-  if (trimmed.includes(CLERK_TEST_SUBADDRESS)) {
+  const localPart = trimmed.split('@', 1)[0];
+  if (localPart.split('+').includes(CLERK_TEST_SUBADDRESS.slice(1))) {
     return trimmed;
   }
📝 Committable suggestion

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

Suggested change
if (trimmed.includes(CLERK_TEST_SUBADDRESS)) {
return trimmed;
}
const localPart = trimmed.split('@', 1)[0];
if (localPart.split('+').includes(CLERK_TEST_SUBADDRESS.slice(1))) {
return trimmed;
}
🤖 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/utils/clerkTestEmail.ts` around lines 14 - 16, Update the
Clerk test email detection around the existing trimmed-email check to match
clerk_test only as an exact subaddress segment in the local part, excluding
near-matches in segments or domains. Align the SignIn and SignUp consumers’
checks with this exact matching behavior, and add regression tests covering
alex+clerk_testing@example.com and alex@clerk_test.example.com.

Comment on lines +5 to +6
export const isClerkTestPhoneNumber = (value: string): boolean => {
return /55501\d\d$/.test(value.replace(/\D/g, ''));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Require a complete US phone number before matching.

The suffix-only regex accepts partial input such as 5550100 and arbitrary longer values ending in the test range. Anchor the normalized value to 10 digits, or 11 digits beginning with 1, and add regression tests for short and overlong inputs.

Proposed fix
 export const isClerkTestPhoneNumber = (value: string): boolean => {
-  return /55501\d\d$/.test(value.replace(/\D/g, ''));
+  const digits = value.replace(/\D/g, '');
+  return /^(?:1)?\d{3}55501\d{2}$/.test(digits);
 };
📝 Committable suggestion

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

Suggested change
export const isClerkTestPhoneNumber = (value: string): boolean => {
return /55501\d\d$/.test(value.replace(/\D/g, ''));
export const isClerkTestPhoneNumber = (value: string): boolean => {
const digits = value.replace(/\D/g, '');
return /^(?:1)?\d{3}55501\d{2}$/.test(digits);
};
🤖 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/utils/clerkTestPhoneNumber.ts` around lines 5 - 6, The
isClerkTestPhoneNumber function currently matches only the suffix, allowing
incomplete or overlong values. Validate the normalized phone number as exactly
10 digits or 11 digits prefixed with 1 before applying the 55501xx test-number
pattern, and add regression tests covering short and overlong inputs.

Sign up for free to 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.

1 participant