Skip to content

Added revalidation of inputs on change.#33

Open
SajidMannikeri17 wants to merge 2 commits into
thunder-id:mainfrom
Infosys:fix/revalidate-on-change
Open

Added revalidation of inputs on change.#33
SajidMannikeri17 wants to merge 2 commits into
thunder-id:mainfrom
Infosys:fix/revalidate-on-change

Conversation

@SajidMannikeri17

@SajidMannikeri17 SajidMannikeri17 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Purpose

Fixes thunder-id/thunderid#3145. Inline validation errors in SignIn / SignUp / Recovery currently persist while the user corrects their input and only clear on blur. Adds an opt-in prop revalidateOnChangeAfterBlur on those components so a rendered error clears the moment the value becomes valid. Also fixes a stale-values closure bug inside useForm that would otherwise cause a one-keystroke lag when on-change validation runs.

<SignIn revalidateOnChangeAfterBlur />
<SignUp revalidateOnChangeAfterBlur />
<Recovery revalidateOnChangeAfterBlur />

Approach

useForm refactor

  • Extracted computeFieldError(value, fieldConfig, requiredMessage) as a pure helper — takes the value as an argument instead of reading a closed-over values state.
  • setValue now validates against the next value via computeFieldError, fixing the one-keystroke lag caused by validateField reading pre-update state after setFormValues(prev => …) queued its update.
  • New config revalidateOnChangeAfterBlur?: boolean (default false). When enabled, setValue re-runs validation only if touched[name] === true, so errors don't appear while initially typing — only while correcting after the first blur.
  • validateField (blur path) unchanged in behavior; delegates to computeFieldError internally.

Prop plumbing

  • Added revalidateOnChangeAfterBlur?: boolean (default false) to BaseSignInProps, BaseSignUpProps, BaseRecoveryProps; passed to their internal useForm calls.
  • SignUp / Recovery inherit the prop via existing BaseXProps & intersections + {...rest} forwarding.
  • SignIn uses an explicit SignInProps, so the prop was added and forwarded to <BaseSignIn> explicitly.

Backward compatibility

  • Default false at every layer — no consumer sees a change unless they opt in.
  • Stale-values fix only affects the on-change validation path, which is gated behind validateOnChange or revalidateOnChangeAfterBlur.
  • No public exports removed or renamed. validateOnChange and revalidateOnChangeAfterBlur are independent.

Related Issues

Related PRs

  • N/A

Checklist

  • Followed the contribution guidelines.
  • Manual test round performed and verified.
  • Documentation provided. (Add links if there are any)
  • Tests provided. (Add links if there are any)
    • Unit Tests
    • Integration Tests
  • Breaking changes. (Fill if applicable)
    • Breaking changes section filled.
    • breaking change label added.

Security checks

  • Followed secure coding standards in WSO2 Secure Coding Guidelines
  • Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets.

Summary by CodeRabbit

  • New Features
    • Added a revalidateOnChangeAfterBlur option for sign-in, sign-up, and account recovery forms to re-run validation as the user types after the field has been blurred (opt-in; default preserves existing behavior).
    • Extended form validation configuration via the shared form hook to support this behavior consistently across fields.
  • Bug Fixes
    • Improved embedded sign-in error handling by better distinguishing recoverable errors from terminal ones to preserve flow state when appropriate.
  • Behavior Changes
    • Form fields may now include additional custom input types for validation generation.

Signed-off-by: Sajid Mannikeri <sajid.mannikeri@ad.infosys.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@SajidMannikeri17, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 1 minute

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0f45cf59-22b3-4a41-a390-02daddd32f21

📥 Commits

Reviewing files that changed from the base of the PR and between 50b522c and b0ce359.

📒 Files selected for processing (5)
  • packages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsx
  • packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx
  • packages/react/src/components/presentation/auth/SignIn/SignIn.tsx
  • packages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsx
  • packages/react/src/hooks/useForm.ts
📝 Walkthrough

Walkthrough

Authentication form components now expose revalidateOnChangeAfterBlur. The option defaults to false, flows into useForm, and enables validation on subsequent changes after a field has been touched. Sign-in also preserves recoverable embedded-flow errors and handles terminal responses before normalization.

Changes

Authentication form behavior

Layer / File(s) Summary
Form validation policy
packages/react/src/hooks/useForm.ts
useForm adds post-blur revalidation, centralizes field error computation, and validates against the next input value.
Authentication component wiring
packages/react/src/components/presentation/auth/{Recovery,SignIn,SignUp}/*
Recovery, sign-in, and sign-up expose the option, default it to false, and pass it into their form configurations; sign-in also includes CUSTOM components in field extraction.
Sign-in terminal response handling
packages/react/src/components/presentation/auth/SignIn/SignIn.tsx
Recoverable embedded errors preserve session state and set a local flow error, while terminal errors retain clearing, URL cleanup, and throwing behavior before normalization.

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

Possibly related PRs

Suggested reviewers: brionmario

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is concise and accurately reflects the main change: enabling input revalidation on change.
Description check ✅ Passed The description covers Purpose, Approach, Related Issues/PRs, Checklist, and Security checks, with enough detail for the PR.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx (1)

591-595: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove hardcoded thunderid literal from data-testid attributes.

As per path instructions, avoid hardcoding the vendor name thunderid in DOM data-* attributes. Since this is an internal test identifier and the brand prefix is likely not load-bearing, the best fix is to avoid the vendor prefix entirely and use data-testid="signin". If a brand-scoped namespace is genuinely required by external testing frameworks, use ${getVendorPrefix(vendor)}-signin instead.

  • packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx#L591-L595: replace data-testid="thunderid-signin" with data-testid="signin".
  • packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx#L601-L606: replace data-testid="thunderid-signin" with data-testid="signin".
  • packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx#L618-L623: replace data-testid="thunderid-signin" with data-testid="signin".
  • packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx#L634-L639: replace data-testid="thunderid-signin" with data-testid="signin".
🤖 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/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx` around
lines 591 - 595, Remove the hardcoded vendor prefix from all four data-testid
attributes in BaseSignIn:
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx at lines
591-595, 601-606, 618-623, and 634-639. Set each identifier to the unprefixed
signin value; no other rendering behavior needs to change.

Source: Path instructions

🧹 Nitpick comments (1)
packages/react/src/hooks/useForm.ts (1)

320-329: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Prevent unnecessary state updates when the field error remains unchanged.

When shouldValidate is true, setFormErrors currently creates and returns a new object on every keystroke, even if the error for the field hasn't changed. Returning the existing state object when there's no change allows React to bail out of unnecessary re-renders.

♻️ Proposed refactor to bail out of state updates
       const error: string | null = computeFieldError(value, getFieldConfig(name), requiredMessage);
       setFormErrors((prev: Record<keyof T, string>) => {
+        if (prev[name] === error || (!error && !(name in prev))) {
+          return prev;
+        }
         const newErrors: Record<keyof T, string> = {...prev};
         if (error) {
           newErrors[name] = error;
🤖 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/react/src/hooks/useForm.ts` around lines 320 - 329, Update the
setFormErrors callback in the shouldValidate path to compare the current error
for name with the newly computed error before cloning state. Return the existing
prev object when the field’s error is unchanged; otherwise preserve the current
add/remove behavior using a copied error map.
🤖 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.

Outside diff comments:
In `@packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx`:
- Around line 591-595: Remove the hardcoded vendor prefix from all four
data-testid attributes in BaseSignIn:
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx at lines
591-595, 601-606, 618-623, and 634-639. Set each identifier to the unprefixed
signin value; no other rendering behavior needs to change.

---

Nitpick comments:
In `@packages/react/src/hooks/useForm.ts`:
- Around line 320-329: Update the setFormErrors callback in the shouldValidate
path to compare the current error for name with the newly computed error before
cloning state. Return the existing prev object when the field’s error is
unchanged; otherwise preserve the current add/remove behavior using a copied
error map.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 50a0fcd0-cae2-4355-8cd9-b32884e12d2a

📥 Commits

Reviewing files that changed from the base of the PR and between a02382f and 3617dcf.

📒 Files selected for processing (5)
  • packages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsx
  • packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx
  • packages/react/src/components/presentation/auth/SignIn/SignIn.tsx
  • packages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsx
  • packages/react/src/hooks/useForm.ts

@SajidMannikeri17
SajidMannikeri17 force-pushed the fix/revalidate-on-change branch from 3617dcf to 50b522c Compare July 20, 2026 09:49

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx (1)

282-294: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move acceptableType outside the component.

Recreating this array on every render violates React dependency rules because it is referenced inside the extractFormFields useCallback but omitted from its dependency array. Moving the constant outside the component resolves the dependency issue and avoids unnecessary allocations.

Define the array outside the component:

const ACCEPTABLE_TYPES = [
  'TEXT_INPUT',
  'PASSWORD_INPUT',
  'EMAIL_INPUT',
  'PHONE_INPUT',
  'OTP_INPUT',
  'SELECT',
  'DATE_INPUT',
  'CUSTOM',
];
♻️ Proposed refactor
-  /**
-     * Component type for which forms validation will be applicable
-    */
-  const acceptableType = [
-    'TEXT_INPUT',
-    'PASSWORD_INPUT',
-    'EMAIL_INPUT',
-    'PHONE_INPUT',
-    'OTP_INPUT',
-    'SELECT',
-    'DATE_INPUT',
-    'CUSTOM',
-  ];

And update its usage below:

-          if (acceptableType.includes(component.type)) {
+          if (ACCEPTABLE_TYPES.includes(component.type)) {
🤖 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/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx` around
lines 282 - 294, Move the acceptableType array out of the component scope,
rename it to ACCEPTABLE_TYPES, and update extractFormFields and any other
references to use the module-level constant so useCallback dependencies remain
stable.
🤖 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/react/src/components/presentation/auth/SignIn/SignIn.tsx`:
- Around line 447-466: Update handleTerminalResponse so terminal error responses
clear state, set the error, and clean up URL parameters, then return true
instead of throwing. Preserve the existing recoverable-error behavior and ensure
initializeFlow and handleSubmit do not enter their catch paths for this handled
terminal response.

---

Nitpick comments:
In `@packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx`:
- Around line 282-294: Move the acceptableType array out of the component scope,
rename it to ACCEPTABLE_TYPES, and update extractFormFields and any other
references to use the module-level constant so useCallback dependencies remain
stable.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: caba69a6-d5ce-4c88-8470-bf439859d14b

📥 Commits

Reviewing files that changed from the base of the PR and between 3617dcf and 50b522c.

📒 Files selected for processing (5)
  • packages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsx
  • packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx
  • packages/react/src/components/presentation/auth/SignIn/SignIn.tsx
  • packages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsx
  • packages/react/src/hooks/useForm.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsx
  • packages/react/src/hooks/useForm.ts

Comment thread packages/react/src/components/presentation/auth/SignIn/SignIn.tsx Outdated
@SajidMannikeri17
SajidMannikeri17 force-pushed the fix/revalidate-on-change branch from 50b522c to 1d96bcf Compare July 20, 2026 10:28
Signed-off-by: Sajid Mannikeri <sajid.mannikeri@ad.infosys.com>
@SajidMannikeri17
SajidMannikeri17 force-pushed the fix/revalidate-on-change branch from 1d96bcf to b0ce359 Compare July 20, 2026 10:47
@ThaminduDilshan

Copy link
Copy Markdown
Member

@SajidMannikeri17 did we test that this fix works and won't cause other issues like call depth exceeding?

@SajidMannikeri17

SajidMannikeri17 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Yes @ThaminduDilshan. We have tested these changes locally via symlink. There are no issues.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Input validation error does not clear dynamically while typing from thunder react SDK

2 participants