Skip to content

fix: add inline email validation feedback in signup flow#50

Merged
kunalverma2512 merged 6 commits into
kunalverma2512:mainfrom
Ushnika09:fix/signup-email-inline-validation
May 16, 2026
Merged

fix: add inline email validation feedback in signup flow#50
kunalverma2512 merged 6 commits into
kunalverma2512:mainfrom
Ushnika09:fix/signup-email-inline-validation

Conversation

@Ushnika09
Copy link
Copy Markdown
Contributor

@Ushnika09 Ushnika09 commented May 15, 2026

📌 Fixes #35

✨ Changes Made

  • Added inline email validation feedback in the signup flow
  • Prevented form submission when the email format is invalid
  • Added aria-invalid support for improved accessibility
  • Enabled noValidate on the form to use custom validation UI
  • Improved UX by showing real-time validation messages below the email field

🛠️ Implementation Details

  • Introduced isEmailValid validation logic
  • Added conditional rendering for inline error feedback
  • Updated submit button disable conditions to include invalid email states

🎥 Demo

Loom walkthrough: [Video Demo](https://www.loom.com/share/b37e7c7b243d4cf2abf0bf2d068d52fb?utm_source=chatgpt.com)

✅ Result

Users now receive instant visual feedback for invalid email input, improving accessibility and overall signup experience.

Summary by CodeRabbit

  • New Features
    • Signup form validates email format in real-time and shows an inline error message for invalid entries.
    • Account creation is blocked when the email is invalid; the "CREATE ACCOUNT" button stays disabled until all required fields (including a valid email) are completed.

Review Change Stack

@github-actions
Copy link
Copy Markdown

🚀 PR Received Successfully

Hello @Ushnika09,

Thank you for taking the initiative to contribute to this project.

Please ensure that your PR follows all project guidelines properly before requesting review.

⚠️ Important Instructions

  • Maintain proper code quality and structure
  • Do not make unnecessary changes/files
  • Ensure responsiveness across devices
  • Follow existing project conventions strictly
  • Attach screenshots/videos for UI-related changes
  • Resolve merge conflicts before requesting review
  • Avoid AI-generated low quality PRs or copied implementations

📌 Mandatory for GSSoC'26 Participants

Joining the community group and announcement channel is compulsory for all contributors participating through GSSoC'26.

Failure to follow contribution guidelines may lead to PR rejection.

We appreciate your effort and wish you a great open-source journey ahead. ✨

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@Ushnika09 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 21 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e359712-5907-4a43-afcd-24e18191374b

📥 Commits

Reviewing files that changed from the base of the PR and between 582f158 and 2d1e560.

⛔ Files ignored due to path filters (1)
  • server/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • frontend/src/pages/SignupPage.jsx
  • server/package.json
📝 Walkthrough

Walkthrough

SignupPage implements custom client-side email validation: a new isEmailValid predicate validates input, the form disables browser validation via noValidate, an inline error appears for invalid-but-nonempty emails, and the submit button is disabled until the email is valid.

Changes

Email Validation in Signup Flow

Layer / File(s) Summary
Validation state and form setup
frontend/src/pages/SignupPage.jsx
Adds isEmailValid state and validateEmail helper; handleRegister blocks submission when isEmailValid is false; <form> uses noValidate.
Email input wiring, inline feedback, and submit gating
frontend/src/pages/SignupPage.jsx
Email onChange updates email and isEmailValid, aria-invalid/aria-describedby are set for invalid-but-nonempty input, an inline "Please enter a valid email address" message is rendered, and the CREATE ACCOUNT button disabled condition includes !isEmailValid.
OTP resend whitespace tweak
frontend/src/pages/SignupPage.jsx
Whitespace-only edit in the OTP resend handler area.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nudge the form with careful care,
Email neat and trimmed and fair,
No browser popup in my hop,
Inline hints keep errors stopped,
Create account waits till it's square.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding inline email validation feedback in the signup flow, which is the primary focus of the changeset.
Linked Issues check ✅ Passed The PR implements all core coding objectives from issue #35: custom inline validation feedback, form submission prevention for invalid emails, noValidate support, aria-invalid/aria-describedby accessibility, and browser validity API-based validation with submit handler guards.
Out of Scope Changes check ✅ Passed All changes are focused on email validation in the signup flow. The whitespace-only change near the OTP resend area appears incidental and does not introduce functional out-of-scope changes.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

Copy link
Copy Markdown

@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: 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 `@frontend/src/pages/SignupPage.jsx`:
- Around line 102-104: The form uses noValidate so client-side HTML validation
is disabled; update the handleRegister function to perform the same checks the
UI enforces before calling authService.register: validate the email format
(e.g., using the existing email regex or validation util), ensure required
fields (password, confirmPassword) meet criteria and match, and return early (or
set errors) if validation fails; this mirrors the disabled-button guard and
prevents authService.register(...) from being called with invalid input.
- Line 19: The inline heuristic in SignupPage.jsx (const isEmailValid) is too
permissive and should be replaced with a single regex-based predicate that trims
input and tests the full address; create or replace with a validator like
validateEmail(email) and set isEmailValid = validateEmail(email.trim()), using a
standard email regex (RFC-like simple pattern) to gate signup UI/actions instead
of the split/includes logic in the current isEmailValid declaration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c849c008-bae1-48aa-ab97-c6c18276bb12

📥 Commits

Reviewing files that changed from the base of the PR and between 12e4428 and 731df6a.

📒 Files selected for processing (1)
  • frontend/src/pages/SignupPage.jsx

Comment thread frontend/src/pages/SignupPage.jsx Outdated
Comment thread frontend/src/pages/SignupPage.jsx Outdated
@kunalverma2512
Copy link
Copy Markdown
Owner

Hey @Ushnika09 👋

Good work on improving the signup UX and adding inline validation feedback. The custom inline error experience is much cleaner than the default browser popup UI. ✨

However, before merging, there are a few important improvements I’d like you to iterate on so the implementation becomes more production-ready and scalable.


Required Improvements

1. Avoid Manual String-Based Email Validation

Currently the validation logic is based on manual string checks similar to:

const isEmailValid =
  email.includes("@") &&
  email.split("@")[1]?.includes(".") &&
  email.split(".").pop().length > 1;

This approach is fragile because malformed emails can still pass validation.

Examples:

abc @gmail.com
test@.com
hello@gmail

Since the input already uses:

type="email"

the browser already provides robust email validation internally.

So instead of manually checking strings, please leverage the browser validity API from the existing type="email" input.

Recommended approach:

<input
  type="email"
  value={email}
  onChange={(e) => {
    setEmail(e.target.value);
    setIsEmailValid(e.target.validity.valid);
  }}
/>

This gives:

  • cleaner implementation
  • browser-level validation
  • better maintainability
  • custom UI flexibility
  • more production-grade behavior

2. Keep noValidate But Add Proper Submit Guard

Keeping:

<form noValidate>

is completely fine because it avoids the default browser popup UI and allows a cleaner custom inline feedback experience.

However, validation should also exist inside the submit handler itself.

Currently validation mainly depends on:

  • disabled button state
  • UI rendering logic

But users can still manually trigger form submission.

So please also add validation inside:

handleRegister()

Example:

if (!isEmailValid) {
  setError("Please enter a valid email address");
  return;
}

This is important because:

  • UI validation is not sufficient
  • submit handlers should always guard invalid states
  • production apps should never rely only on disabled buttons

3. Important Learning Point

Please also explore the difference between:

  • UI validation
  • browser validation
  • backend validation

Frontend validation mainly improves UX.
Actual security/verification should always happen on backend as well.

This is an important frontend engineering concept to learn early while contributing to larger projects.


4. Accessibility

Nice job adding:

aria-invalid

That is a good accessibility improvement 👍

In future iterations, also explore:

  • aria-describedby
  • screen-reader-friendly error messages
  • associating errors properly with inputs

These small things make UI implementations much more polished and accessible.


Overall the feature direction is good and the UX improvement is meaningful.
Now focus on making the implementation:

  • more robust
  • standards-based
  • scalable
  • production-oriented

Please iterate on these points and push the next commit accordingly 🚀

@kunalverma2512
Copy link
Copy Markdown
Owner

@Ushnika09

Also, please prepare and verify multiple test cases for the email input field covering as many edge cases as possible before the next commit.

Examples:

  • valid emails
  • emails with spaces
  • missing @
  • missing domain
  • multiple dots
  • special characters
  • uppercase/lowercase combinations
  • subdomains
  • malformed domain patterns

This will help ensure the validation logic behaves consistently across different scenarios and improves overall robustness of the implementation.

@Ushnika09
Copy link
Copy Markdown
Contributor Author

🎥 Loom Walkthrough: https://www.loom.com/share/8255b4a607434d6487e63d75a6e380a7

Covering multiple edge cases for robust validation handling.

@Ushnika09
Copy link
Copy Markdown
Contributor Author

@coderabbitai please re-review the latest changes. Addressed the email validation robustness, submit handler safeguards, accessibility improvements, and tested multiple edge cases.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the PR details and diff
gh pr view 50 --repo kunalverma2512/CodeLens --json files,headRefName,baseRefName

# Get the diff for the PR
gh pr diff 50 --repo kunalverma2512/CodeLens

Length of output: 4048


@Ushnika09 Great progress on this iteration! The implementation is significantly more robust than the initial version. Here's the detailed re-review:


✅ What's Been Well Addressed

Feedback Status
Browser validity API (e.target.validity.valid) ✅ Implemented
Submit handler guard in handleRegister ✅ Added
noValidate on form ✅ Added
aria-invalid on input ✅ Added
Button disabled includes !isEmailValid ✅ Added
min-h-[16px] wrapper (prevents layout shift) ✅ Nice touch
role="alert" on error paragraph ✅ Added

🔴 Remaining Issue — aria-describedby Is Misused

This is a semantic accessibility bug. Currently:

// ❌ aria-describedby is placed on the error <p> itself, and the <p> has no id
<p
  aria-describedby="email-error"  // ← wrong element, wrong placement
  role="alert"
  ...
>
  Please enter a valid email address
</p>

aria-describedby must be placed on the input, pointing to the id of the element that describes it (the error message). The correct pattern is:

// ✅ aria-describedby on the input, pointing to the error element's id
<input
  type="email"
  aria-invalid={email.length > 0 && !isEmailValid}
  aria-describedby={email && !isEmailValid ? "email-error" : undefined}
  ...
/>

// ✅ error <p> has the matching id
<p
  id="email-error"
  role="alert"
  className="..."
>
  Please enter a valid email address
</p>

This is important because screen readers use aria-describedby to announce the error message when the input receives focus — but only if it's wired correctly.


🟡 Minor — Redundant String Checks in validateEmail

const validateEmail = (value, validity) => {
  const trimmedEmail = value.trim();
  return (
    validity.valid &&              // ← already validates @ and . for type="email"
    trimmedEmail.includes("@") && // ← redundant
    trimmedEmail.split("@")[1]?.includes(".")  // ← redundant
  );
};

Since validity.valid from a type="email" input already enforces proper email format including the presence of @ and a valid domain, the extra string checks are redundant. You can simplify to:

const validateEmail = (value, validity) => {
  return value.trim().length > 0 && validity.valid;
};

This keeps the trimming guard (prevents whitespace-only input being seen as valid) while leveraging the browser's full validation capability.


Summary

Fix the aria-describedby misuse — it's the one remaining accessibility concern. The redundant string checks are a minor cleanup. Everything else looks production-ready. Once these are addressed, the implementation will be clean and robust. 🚀

(˳◕ᴗ◕)˳ ♡

✅ Actions performed

Full review triggered.

@Ushnika09
Copy link
Copy Markdown
Contributor Author

@coderabbitai please re-review the latest changes.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest diff for the PR
gh pr diff 50 --repo kunalverma2512/CodeLens

# Also get the current file content
gh api repos/kunalverma2512/CodeLens/contents/frontend/src/pages/SignupPage.jsx?ref=fix/signup-email-inline-validation --jq '.content' | base64 -d

Length of output: 3879


@Ushnika09 Great progress — almost everything is clean and production-ready now! Here's the updated review:


✅ Fully Addressed

Feedback Status
validateEmail simplified (redundant string checks removed) ✅ Fixed
aria-describedby moved to the <input> ✅ Fixed
Submit handler guard (if (!isEmailValid) return) ✅ Added
noValidate on form ✅ Present
aria-invalid on input ✅ Present
min-h-[16px] layout shift guard ✅ Present
role="alert" on error <p> ✅ Present
Button disabled includes !isEmailValid ✅ Present

🔴 One Remaining Bug — id="email-error" Is Still Missing

The input correctly declares:

aria-describedby={email && !isEmailValid ? "email-error" : undefined}

But the error <p> element does not have the matching id:

// ❌ Missing id — aria-describedby points to nothing
<p
  role="alert"
  className="text-xs font-black uppercase tracking-widest text-red-600"
>
  Please enter a valid email address
</p>

Without id="email-error", the aria-describedby reference is broken — screen readers cannot locate the element and will silently ignore the association. The fix is a one-line addition:

// ✅ Add id to the <p>
<p
  id="email-error"
  role="alert"
  className="text-xs font-black uppercase tracking-widest text-red-600"
>
  Please enter a valid email address
</p>

Summary

Just one line remaining — add id="email-error" to the error <p>. Once that's in, the entire implementation will be clean, accessible, and production-ready. 🚀

(˳◕ᴗ◕)˳ ♡

✅ Actions performed

Full review triggered.

@kunalverma2512
Copy link
Copy Markdown
Owner

@Ushnika09 update?

@Ushnika09
Copy link
Copy Markdown
Contributor Author

@coderabbitai please re-review the latest changes. Resolved merge conflicts, preserved the GitHub signup flow alongside email registration, and verified the accessibility + validation improvements are still functioning correctly.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest diff for the PR
gh pr diff 50 --repo kunalverma2512/CodeLens

# Also get the current file content
gh api "repos/kunalverma2512/CodeLens/contents/frontend/src/pages/SignupPage.jsx?ref=fix/signup-email-inline-validation" --jq '.content' | base64 -d

Length of output: 10708


@Ushnika09 This is a clean, complete implementation — everything checks out. Here's the final summary:


✅ All Issues Resolved

Feedback Status
validateEmail simplified — uses validity.valid + trim() only ✅ Fixed
aria-describedby on <input> pointing to "email-error" ✅ Fixed
id="email-error" on the error <p> Fixed in this iteration
role="alert" on error <p> ✅ Present
aria-invalid on input ✅ Present
Submit handler guard (if (!isEmailValid) return) ✅ Present
noValidate on form ✅ Present
Button disabled includes !isEmailValid ✅ Present
min-h-[16px] layout shift guard ✅ Present
GitHub signup flow preserved ✅ Confirmed
Merge conflicts resolved ✅ Confirmed

The id="email-error" fix completes the aria-describedby linkage — screen readers can now correctly announce the error message when the email input receives focus. The implementation is clean, accessible, and production-ready. 🚀

(˳◕ᴗ◕)˳ ♡


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@Ushnika09
Copy link
Copy Markdown
Contributor Author

@coderabbitai while testing I noticed emails like user@gmail were still being treated as valid. Also, when adding a trailing ., it becomes invalid, and after adding something after the dot it suddenly becomes valid again, which is not ideal behavior.

Updating the validation logic from:

return value.trim().length > 0 && validity.valid;

to:

return (
  value.trim().length > 0 &&
  validity.valid &&
  value.split("@")[1]?.includes(".")
);

fixes the issue properly while still using the browser validity API. Please review it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Tip

For best results, initiate chat on the files or code changes.

@Ushnika09 Your observation is accurate and well-diagnosed. Here's the full breakdown:


Why user@gmail Passes validity.valid

HTML5 email validation will not catch errors like a user entering john@gmail instead of john@gmail.com — because by specification, a TLD is not required, as it is a perfectly valid email on a local network. MDN confirms this explicitly: type="email" accepts username@domain or username@domain.tld. So validity.valid passing for user@gmail is correct browser behavior, not a browser bug.


Is the Proposed Fix Sound?

Yes — and importantly, it is not redundant this time. In the previous iteration, includes(".") was redundant because validity.valid already catches @-less or otherwise structurally broken addresses. But validity.valid genuinely does not enforce the presence of a dot in the domain, so this additional check fills a real gap:

// ✅ Correct — the dot check is non-redundant here
const validateEmail = (value, validity) => {
  return (
    value.trim().length > 0 &&
    validity.valid &&
    value.split("@")[1]?.includes(".")
  );
};

This approach:

  • Keeps validity.valid as the primary structural check
  • Adds a targeted, minimal constraint for the TLD-less edge case
  • Is readable and easy to reason about

One Minor Edge Case to Consider

user@.com — but validity.valid already rejects this (empty label before the dot), so the combination handles it correctly. ✅


The fix is clean and production-appropriate. Go ahead and push it. 🚀

(˳◕ᴗ◕)˳ ♡


✏️ Learnings added
Learnt from: Ushnika09
URL: https://github.com/kunalverma2512/CodeLens/pull/50

Timestamp: 2026-05-16T03:55:36.799Z
Learning: In the `validateEmail` function in `frontend/src/pages/SignupPage.jsx`, `validity.valid` for `type="email"` inputs does NOT require a TLD. Addresses like `usergmail` pass `validity.valid` because the HTML5 spec allows `usernamedomain` without a TLD. The correct `validateEmail` implementation should add `value.split("@")[1]?.includes(".")` alongside `validity.valid` to enforce TLD presence: `return value.trim().length > 0 && validity.valid && value.split("@")[1]?.includes(".")`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@kunalverma2512
Copy link
Copy Markdown
Owner

@Ushnika09

Good.

This iteration is properly refined now and the validation handling looks much more production-oriented after the edge case analysis and fixes.

Maintain this level of debugging depth, implementation quality, and iteration discipline in future contributions as well.

@kunalverma2512 kunalverma2512 merged commit 89f2178 into kunalverma2512:main May 16, 2026
1 check passed
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.

UI/UX: Add Custom Frontend Email Validation Feedback in Signup Flow

2 participants