setCustomValidity() not sending error message to HTML despite detecting error

I am having a issue where I am trying to use setCustomValidity() in order to make custom error messages with the credit card project I am working on. This is all from a learning assignment for school, so some of the code is a little advanced and new to work with.

Below is the form I am working with. It is supposed to allow the user to fill out credit card information while using custom error messages to alert the user of blank fields.

The code works in detecting if the user fails to fill out the name input field ( <label for="cardName">Name*</label> and function validateName() ).

However, It is failing to do so when working with radio buttons with the credit cards ( <fieldset id="cards"> and function validateCredit() { ). The JS code is able to detect the user isn’t inputting anything but will not send any error to the HTML. Then it completely fails to do so for the card number ( <label for="cardNumber">Credit Card Number*</label> and function validateNumber() )


      <form id="payment" name="payment" method="post" action="co_temp.html">         
         <fieldset id="creditcard">
            <legend>Credit Information</legend>

            <label for="cardName">Name*</label>
            <input name="cardName" id="cardName" required type="text" />              

            <fieldset id="cards">
               <label class="cardLabel">Credit Card*</label>
               <label class="cardLabel">
                  <input name="credit" value="amex" type="radio" required />
                  <img src="co_amex.png" alt="American Express" />
               <label class="cardLabel">               
                  <input name="credit" value="discover" type="radio" />
                  <img src="co_discover.png" alt="Discover" />
               <label class="cardLabel">                  
                  <input name="credit" value="master" type="radio"  />
                  <img src="co_master.png" alt="MasterCard" />
               <label class="cardLabel">                  
                  <input name="credit" value="visa" type="radio"  />
                  <img src="co_visa.png" alt="Visa" />

            <label for="cardNumber">Credit Card Number*</label>
            <input name="cardNumber" id="cardNumber" required type="text"

            <label for="expMonth">Expiration Date*</label>
            <select id="expMonth" name="expMonth">
               <option value="mm">mm</option>
               <option value="01">01</option>
               <option value="01">02</option>
               <option value="01">03</option>
               <option value="01">04</option>
               <option value="01">05</option>
               <option value="01">06</option>
               <option value="01">07</option>
               <option value="01">08</option>
               <option value="01">09</option>
               <option value="01">10</option>
               <option value="01">11</option>
               <option value="01">12</option>
            <span> / </span>
            <select id="expYear" name="expYear">
               <option value="yy">yy</option>
               <option value="2018">2018</option>
               <option value="2019">2019</option>
               <option value="2020">2020</option>
               <option value="2021">2021</option>
               <option value="2022">2022</option>

            <label for="cvc">CVC*</label>
            <input name="cvc" id="cvc" required pattern="^\d{3,4}$" type="text"/>

         <p id="footnote">* - Required Item</p>        
         <input type="submit" id="subButton" value="Submit Payment" />         

Here is the JavaScript code:

window.addEventListener("load", function() {
	document.getElementById("subButton").onclick = runSubmit;
	document.getElementById("cardName").oninput = validateName;
	document.getElementById("cardNumber").oninput = validateNumber;

function runSubmit() {

// Not working at all
function validateNumber() {
	var cardNumber = document.getElementById("cardNumber");
	if (cardNumber.validity.valueMissing) {
		console.log("No card detected")
		cardNumber.setCustomValidity("Enter your card Number");
	} else if (cardNumber.validity.patternMismatch) {
		console.log("Invalid card detected")
		cardNumber.setCustomValidity("Enter a valid card number");
	} else {

// Not working. Detects but doesn't send error. 
function validateCredit() {
	var creditCard =[0];
	if (creditCard.validity.valueMissing) {
		console.log("No button selected")
		creditCard.setCustomValidity("Select your credit card")
	} else {

// Working
function validateName() {
	var cardName = document.getElementById("cardName");
	if (cardName.validity.valueMissing) {
		cardName.setCustomValidity("Enter your name as it appears on your card");
	} else {
		cardName.setCustomValidity(" ");


Weird, because it works for me. It doesn’t allow me to leave anything empty. It doesn’t display all the errors at once, but it does show them if I submit the form after fixing one.

Are you using a specific browser or did you test it on a different one?

I typed in “hello” as the name, pressed submit and saw no errors pop up. I am using Google Chrome that is up to data as far as I know.

That’s because you’re only validating that the name is not empty; you’re not forcing your users to enter a specific number of characters:

// This would check that the name is at least 3 characters long:
if (cardName.length < 3 || cardName.validity.valueMissing) {
  cardName.setCustomValidity("Enter a valid name");
} else {

I meant that the errors should pop up for the unfilled sections. A error should pop up for the credit card number and radio button selector. The expiration date and such will be added later on after I figure out why these don’t display.

I get it :slight_smile:.

The thing is, that’s the default behavior; it will not show the popup for every error, only for the first. It varies from browser to browser, but on Firefox, the other fields get a red border to indicate an error and if you hover over the field, you will see the error text.

Here you can see the default behavior.

1 Like