I am creating a contact form and validating using javascript event listener. The invalid event listener is working for the input elements from the deafult required class added to the input fields. However, it is not working for the textarea despite also giving the textarea field the "required" class?
document.forms.form01.addEventListener("invalid", function(e) {
e.preventDefault();
e.target.classList.add('invalid');
}, true);
document.forms.form01.addEventListener("focus", function(e) {
e.preventDefault();
[...e.target.form.querySelectorAll('.invalid')]
.forEach(elm => elm.classList.remove('invalid'));
}, true);
form {
width: 100%;
max-width: 500px;
margin: 0 auto;
}
form label {
display: inline-block;
width: 100%;
font-weight: bold;
}
form input[type="text"],
form input[type="email"],
form textarea {
width: 100%;
padding: 10px;
margin-top: 5px;
margin-bottom: 20px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 16px;
font-family: sans-serif;
}
form input[type="submit"] {
display: block;
width: 100%;
padding: 10px;
margin-top: 20px;
background-color: #4CAF50;
color: #fff;
font-size: 16px;
font-weight: bold;
border: none;
border-radius: 5px;
}
form .form-control.error input,
form .form-control.error textarea {
border-color: #f44336;
}
form .form-control.error small {
visibility: visible;
color: #f44336;
font-size: 14px;
}
form .form-control.success input,
form .form-control.success textarea {
border-color: #4CAF50;
}
form .form-control.success small {
visibility: hidden;
color: #4CAF50;
font-size: 14px;
}
.contact-form .required-label {
color: #ff0000;
font-weight: 400;
}
.form-group {
position: relative;
height: 100px;
}
div.feedback {
border: solid thin red;
position: absolute;
left: 0;
bottom: -10px;
width: 100%;
padding: .2em;
background-image: linear-gradient(180deg, #fff, #ddd 40%, #ccc);
display: none;
}
input.invalid~div.feedback {
display: block;
}
input:invalid {
border: thin solid red;
}
<!-- Bootstrap CSS-5.3.3 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<form action="" name="form01" method="post" class="pt-md-4 pt-5 pb-5 mb-4 ">
<div class="form-group">
<label for="name" class="form-label">Name<span class="required-label"> *</span></label>
<input type="text" class="form-control" id="fname" style="height:40px" name="fname" placeholder="First Name" required>
<div class="feedback">This needs to be a name</div>
</div>
<div class="form-group mt-3">
<label for="email" class="form-label">Email address<span class="required-label"> *</span></label>
<input type="email" class="form-control" id="email" name="email" placeholder="name@example.com" required>
<div class="feedback">Invalid email!</div>
</div>
<div class="form-group mt-5">
<label for="message" class="form-label">Message<span class="required-label"> *</span></label>
<textarea class="form-control" id="message" name="message" placeholder="your message..." rows="3" required></textarea>
<div class="feedback">Empty message!</div>
</div>
<br>
<br>
<button>Submit</button>
</form>
`
You are not telling us what makes the textarea input invalid, but in any case you only style inputs, not textareas:
input.invalid ~ div.feedback { ... } this shows feedback only for inputs.
input:invalid { ... } this draws the red border only for inputs
Possible solutions
Add the textarea
/* show feedback when either input or textarea has .invalid */
input.invalid ~ .feedback,
textarea.invalid ~ .feedback {
display: block;
}
/* red border when browser considers either invalid */
input:invalid,
textarea:invalid {
border: thin solid red;
}
(shorter):
:is(input, textarea).invalid ~ .feedback { display: block; }
:is(input, textarea):invalid { border: thin solid red; }
Use bootstrap on the field-control
.form-control.invalid ~ .feedback {
display: block;
}
.form-control:invalid {
border: thin solid red;
}
You might want to wait with testing the validity until submit