I want to create floating labels that resize dynamically when an input is clicked, similar to modern forms. I am using vanilla JS exclusively for this task.
Currently, the setup works with the <input>
tag. However, it does not work with the <textarea>
tag. Despite spending a significant amount of time trying to troubleshoot this issue, I cannot figure out why the <textarea>
element is returning null when I attempt to add the .active class to it. This class is essential for the font and animation to function correctly. Below is the current JS script:
// add active class
const handleFocus = (e) => {
const target = e.target;
target.parentNode.classList.add('active');
target.setAttribute('placeholder', target.getAttribute('data-placeholder'));
};
// remove active class
const handleBlur = (e) => {
const target = e.target;
if(!target.value) {
target.parentNode.classList.remove('active');
}
target.removeAttribute('placeholder');
};
// register events
const bindEvents = (element) => {
const floatField = element.querySelector('input');
floatField.addEventListener('focus', handleFocus);
floatField.addEventListener('blur', handleBlur);
};
// get DOM elements
const init = () => {
const floatContainers = document.querySelectorAll('.float-container');
console.log(document.querySelectorAll('.float-container'));
floatContainers.forEach((element) => {
if (element.querySelector('input').value) {
element.classList.add('active');
}
bindEvents(element);
});
};
return {
init: init
};
})();
window.onload=FloatLabel.init();
Despite confirming that the <textarea>
element is present in the list of elements retrieved, attempting to add the active class when checking for text inside the textarea results in a null value and breaks the script.
I'm uncertain if there is something I'm overlooking or if there is a fundamental aspect of the problem that I do not understand. I have verified that the TypeError is not related to the DOM not being ready. Additionally, the script is positioned at the bottom of the PHP file and the defer keyword has been added as a precaution. While I understand that using defer on a script at the bottom of the document may not have any impact, I have included it nonetheless. Below are the CSS classes used:
.float-container {
width: 66%;
position: relative;
}
.float-container.small input {
width: 50%;
outline-offset: 1px;
font-size: 16px;
padding: 16px 4px 10px 4px;
border-radius: 4px;
}
.float-container.small textarea {
width: 100%;
outline-offset: 1px;
font-size: 16px;
padding: 16px 4px 10px 4px;
border-radius: 4px;
color: red;
}
.float-container.large input {
width: 100%;
outline-offset: 1px;
font-size: 16px;
padding: 16px 4px 10px 4px;
border-radius: 4px;
}
.float-container.active {
border: 2px solid #1A57FF;
outline: 2px solid rgba(26, 87, 255, 0.3);
border-radius: 4px;
}
.float-container.active label {
transform: translate(0, 4px) scale(.75);
}
.floating-text {
position: absolute;
font-size: 16px;
text-decoration: underline;
color: rgb(100, 100, 100);
transform: translate(0, 16px) scale(1);
transform-origin: top left;
transition: all .1s ease-in-out;
}
Lastly, here is a snippet of the form from the document:
<div id="floatContainer" class="float-container small">
<label for="fName" class="floating-text">First Name</label>
<input type="text" id="fName" name="fName" data-placeholder="First name"><br>
</div>
<p id="fName-validate" class="form-validate-text"></p>
<div id="floatContainer" class="float-container small">
<label for="lName" class="floating-text">Last Name</label>
<input type="text" id="lName" name="lName" data-placeholder="Last name"><br>
</div>
<p id="lName-validate" class="form-validate-text"></p>
<div id="floatContainer" class="float-container small">
<label for="email" class="floating-text">Email</label>
<input type="text" id="email" name="email" data-placeholder="Email"><br>
</div>
<p id="email-validate" class="form-validate-text"></p>
<div id="floatContainer" class="float-container small active">
<label for="phoneNumber" class="floating-text">Phone Number</label>
<input type="tel" id="phoneNumber" name="phoneNumber" data-placeholder="Phone"><br>
</div>
<p id="phoneNumber-validate" class="form-validate-text"></p>
<div id="floatContainer" class="float-container small">
<label for="problemDesc" class="floating-text">Description of problem</label>
<textarea id="problemDesc" name="problemDesc"></textarea><br>
</div>