-4

I'm building a user registration form using HTML, CSS, and JavaScript, with Firebase Authentication handling the registration.

I wanted to add a common feature where errors are prompted when using an invalid email, a short password, or mismatched passwords. This is quite common with many registration forms.

I expected inline error messages like “Invalid email format” or “Passwords do not match”) to appear under the form fields when validation fails. For some reason, it doesn't show up or give that prompt. It's as if the JS doesn't trigger to show that.

const form = document.getElementById('register-form');
const emailInput = document.getElementById('email');
const passwordInput = document.getElementById('password');
const repeatPasswordInput = document.getElementById('repeat-password');

function resetErrors() {
  [emailInput, passwordInput, repeatPasswordInput].forEach(input => {
    input.classList.remove('error');
    document.getElementById(`${input.id}-error`).classList.remove('show');
  });
}

function validateInputs() {
  let hasError = false;
  resetErrors();

  if (!emailInput.value.includes('@') || !emailInput.value.includes('.')) {
    emailInput.classList.add('error');
    document.getElementById('email-error').classList.add('show');
    hasError = true;
  }

  if (passwordInput.value.length < 6 || passwordInput.value.length > 32) {
    passwordInput.classList.add('error');
    document.getElementById('password-error').classList.add('show');
    hasError = true;
  }

  if (passwordInput.value !== repeatPasswordInput.value) {
    repeatPasswordInput.classList.add('error');
    document.getElementById('repeat-password-error').classList.add('show');
    hasError = true;
  }

  return !hasError;
}

form.addEventListener('submit', (e) => {
  e.preventDefault();
  if (!validateInputs()) {
    alert('Please fix the highlighted fields.');
  } else {
    alert('Form submitted!');
    form.reset();
    resetErrors();
  }
});
.register-container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 4rem;
  padding: 5rem 2rem;
  max-width: 1100px;
  margin: 0 auto;
  flex-wrap: wrap;
}

#register-form {
  flex: 1;
  max-width: 400px;
  background-color: #fcfcfc;
  padding: 2rem 2.5rem;
  border-radius: 8px;
  box-shadow: 0 4px 8px rgba(122, 132, 80, 0.2);
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  box-sizing: border-box;
}



#register-form label {
  display: block;
  margin-bottom: 0.3rem;
  font-weight: 600;
  color: #4b5221;
}

#register-form input {
  width: 100%;
  padding: 0.6rem 0.8rem;
  margin-bottom: 1rem;
  border: 1.5px solid #c8ceaa;
  border-radius: 6px;
  font-size: 1rem;
  transition: border-color 0.3s ease;
}

#register-form input:focus {
  border-color: #7a8450;
  outline: none;
}

#submit {
  width: 100%;
  background-color: #7a8450;
  border: none;
  color: white;
  font-weight: 700;
  padding: 0.75rem;
  border-radius: 25px;
  font-size: 1.1rem;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.form {
  text-align: center;
  margin-top: 1.5rem;
  font-size: 0.95rem;
  color: #555;
}

.form a {
  color: #7a8450;
  font-weight: 600;
  text-decoration: none;
}

.form a:hover {
  text-decoration: underline;
}

.register-tip {
  font-size: 0.8rem;
  color: #7a8450;
  font-style: italic;
  margin-top: 0rem;
  margin-bottom: 1rem;
}

input.error {
  border: 2px solid red;
  background-color: #ffe6e6;
}

.error-message {
  color: red;
  font-size: 0.8rem;
  margin-top: 0rem;
  margin-bottom: 0.2rem;
  display: none;
}

#register-form .error-message.show {
  display: block;
}


@media screen and (max-width: 768px) {
  .register-container {
    padding: 2rem 1rem;
  }

  #register-form,
  .register-info {
    max-width: 100%;
  }
}
<form id="register-form">
  <label for="email">Email</label>
  <input type="email" id="email" placeholder="Email" />
  <div class="error-message" id="email-error">Please enter a valid email</div>

  <label for="password">Password</label>
  <input type="password" id="password" placeholder="Password" />
  <div class="error-message" id="password-error">Password too short</div>

  <label for="repeat-password">Repeat Password</label>
  <input type="password" id="repeat-password" placeholder="Repeat Password" />
  <div class="error-message" id="repeat-password-error">Passwords do not match</div>

  <button type="submit">Register</button>
</form>

  • I added console.log to confirm validateInputs runs (it sends the reports as intended).
  • Checked CSS for conflict. The displays should be correct.
5
  • Because your form is validating your input type email before. If you want to see your text message use novalidate attribute on the form Commented Jul 18 at 11:20
  • 2
    Appears to work fine here -> jsfiddle.net/f0q3ov1p But I can't say if that 100% reproduces your setup, because we don't know how exactly you connected those snippets you have shown us. jsfiddle inserts the JS code at the end of body, so the elements it tries to access will exist already at that point. If you placed it somewhere else, you might need to bind it to load/ready events. Commented Jul 18 at 11:20
  • Made it into a stack snippet. As C3roe said it seems to work, so the issue must lie somewhere else. Do you have any errors shown in your console? Commented Jul 18 at 12:04
  • I think he is not seeing the error message because he may not write the @ in the email input and then the form input type email is validating and showing error before showing his messages. As C3roe pointed as well besides this pointed behaviour his code works as exprected Commented Jul 18 at 12:15
  • I don't get why this question was closed because it should be a duplicate of this -- that question does not even have a proper answer. No doubt that is question is a duplicate, so try have a look at this, this, this or this. Commented Jul 19 at 6:34

2 Answers 2

0

Instead of using the submit event of the form to decide if the values are valid, use the build-in form validation. If you set the required attribute on the input elements that need to be valid the form will only submit if they are valid.

Listen for the invalid event, and e.preventDefault() with the useCapture flag set to true on addEventListener(). This will prevent the default error message in showing up.

A side note: It would be obvious to set the minLength and maxLength on the password. The issue is that you cannot type more than 32 characters into the input when setting maxLength, and that combined with the hidden characters in the password field makes it difficult for the user to see what the password ends after 32 characters (btw. setting a max on password length is actually a bad idea).

const form = document.forms.register_form;

form.addEventListener('input', e => {
  let form = e.target.form;
  if (e.target.validity.valid) e.target.classList.remove('error');
  if (e.target.name == 'password') {
    if (e.target.value.length > 5) e.target.classList.remove('tooshort');
    if (e.target.value.length < 33) e.target.classList.remove('toolong');
    // copy the value of password to the pattern of repeat_password
    form.repeat_password.pattern = e.target.value;
  }
});

form.addEventListener('invalid', e => {
  e.preventDefault();
  console.log(e.target.minLength > 0);
  e.target.classList.add('error');
  if (e.target.name == 'password') {
    if (e.target.value.length < 6) e.target.classList.add('tooshort');
    if (e.target.value.length > 32) e.target.classList.add('toolong');
  }
}, true);

form.addEventListener('submit', e => {
  e.preventDefault();
  alert('Form submitted!');
  e.target.reset();
});
.register-container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 4rem;
  padding: 5rem 2rem;
  max-width: 1100px;
  margin: 0 auto;
  flex-wrap: wrap;
}

#register_form {
  flex: 1;
  max-width: 400px;
  background-color: #fcfcfc;
  padding: 2rem 2.5rem;
  border-radius: 8px;
  box-shadow: 0 4px 8px rgba(122, 132, 80, 0.2);
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  box-sizing: border-box;
}



#register_form label {
  display: block;
  margin-bottom: 0.3rem;
  font-weight: 600;
  color: #4b5221;
}

#register_form input {
  width: 100%;
  padding: 0.6rem 0.8rem;
  margin-bottom: 1rem;
  border: 1.5px solid #c8ceaa;
  border-radius: 6px;
  font-size: 1rem;
  transition: border-color 0.3s ease;
}

#register_form input:focus {
  border-color: #7a8450;
  outline: none;
}

#submit {
  width: 100%;
  background-color: #7a8450;
  border: none;
  color: white;
  font-weight: 700;
  padding: 0.75rem;
  border-radius: 25px;
  font-size: 1.1rem;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.form {
  text-align: center;
  margin-top: 1.5rem;
  font-size: 0.95rem;
  color: #555;
}

.form a {
  color: #7a8450;
  font-weight: 600;
  text-decoration: none;
}

.form a:hover {
  text-decoration: underline;
}

.register-tip {
  font-size: 0.8rem;
  color: #7a8450;
  font-style: italic;
  margin-top: 0rem;
  margin-bottom: 1rem;
}

input.error {
  border: 2px solid red;
  background-color: #ffe6e6;
}

label:has(input[class="error"])+.error-message,
label:has(input.tooshort)~.error-message.tooshort,
label:has(input.toolong)~.error-message.toolong {
  display: block;
}

.error-message {
  color: red;
  font-size: 0.8rem;
  margin-top: 0rem;
  margin-bottom: 0.2rem;
  display: none;
}

#register-form .error-message.show {
  display: block;
}


@media screen and (max-width: 768px) {
  .register-container {
    padding: 2rem 1rem;
  }

  #register-form,
  .register-info {
    max-width: 100%;
  }
}
<form id="register_form">
  <label>
    <span>Email</span>
    <input type="email" name="email" placeholder="Email" required>
  </label>
  <div class="error-message">Please enter a valid email</div>

  <label>
    <span>Password</span>
    <input type="password" name="password" placeholder="Password"
     pattern=".{6,32}" required>
  </label>
  <div class="error-message tooshort">Password too short</div>
  <div class="error-message toolong">Password too long</div>

  <label>
    <span>Repeat Password</span>
    <input type="password" name="repeat_password" placeholder="Repeat Password"
      pattern="" required>
  </label>
  <div class="error-message">Passwords do not match</div>

  <button type="submit">Register</button>
</form>

Sign up to request clarification or add additional context in comments.

Comments

-1

It looks like your validation logic is mostly correct, and you're already calling validateInputs() on form submission which is great.

However, based on your description, the issue seems to be that the inline error messages aren’t showing, even though the logic to add the .show class is being called.

  1. Missing .show class styling? In your CSS, you have this rule:
#register-form .error-message.show {
  display: block;
}

That selector is very specific: it only applies .show to elements inside #register-form that have both classes error-message and show, Make sure:

You are not accidentally applying .show to elements outside the #register-form, or

The error-message divs are not outside the form (which they aren't, based on your code — so that’s good!).

Ensure the IDs in your HTML match exactly the ones used in your JS:

<div class="error-message" id="email-error">Please enter a valid email</div>

And:

document.getElementById('email-error').classList.add('show');

3.Try adding logs to confirm element is selected Temporarily add this inside your validateInputs() to make sure the DOM is being accessed correctly:

console.log(document.getElementById('email-error')); // Should log the div element

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.