hamscript
hamscript

Reputation: 73

Animating the labels on input focus with CSS and JavaScript

I have a few input fields and I want their labels to scale down and slide at the top on focus. I have managed to achieve this with CSS and JavaScript but it only animates the first label on the page.

The code JS below uses "querySelector" to target the labels. I've also tried using "getElementsByClassName" and "querySelectorAll". What that does is animate all the labels on the page when I focus on just one input field.

I'd like to only animate the label attached to input. Any help with this would be greatly appreciated.

document.addEventListener("change", function(event) {

  if (event.target && event.target.matches(".js_form-input")) {

    event.preventDefault();

    var inputField = event.target;
    var inputLabels = document.querySelector(".label-span");

    if (inputField.value) {
      inputLabels.style.top = "-1.5rem";
    } else {
      inputLabels.style.top = "0rem";
    }
  }
});
.input {
  width: 100%;
  border: 0;
  border-bottom: solid 1px grey;
  padding-left: 1rem;
  margin-bottom: 2rem;
  color: $c_pop;
  padding-bottom: 0.7rem;
}

.input-label {
  position: relative;
}

.label-span {
  position: absolute;
  top: 0;
  left: 1rem;
  transition: all 0.2s;
}

.input-label {
  font-size: 0.9rem;
}

.input:focus+.label-span {
  top: -1.5rem;
  left: 0.5rem;
  font-size: 0.7rem;
}
<div class="input-container">
  <label class="input-label" for="#">
    <input class="input js_form-input" type="text">
    <span class="label-span">First Name</span>
  </label>
</div>

<div class="input-container">
  <label class="input-label" for="#">
    <input class="input js_form-input" type="text">
    <span class="label-span">Surname</span>
  </label>
</div>

<div class="input-container">
  <label class="input-label" for="#">
    <input class="input js_form-input" type="text">
    <span class="label-span">Email</span>
  </label>
</div>

I've also tried this JS method:

var inputField = event.target;
        var inputLabels = document.querySelectorAll(".label-span");
    
         [].slice.call(inputLabels).forEach(function(label){
          if (inputField.value) {
            label.style.top = "-1.5rem";
           } else {
            label.style.top = "0rem";
           }
       });

Upvotes: 3

Views: 3778

Answers (3)

Kumar Gaurav
Kumar Gaurav

Reputation: 738

Another trick to achieve same result without Javascript.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: sans-serif;
}
.input-container {
  padding: 20px;
}
.input {
  width: 100%;
  border: 0;
  border-bottom: solid 1px grey;
  padding-left: 1rem;
  margin-bottom: 2rem;
  color: #000;
  padding-bottom: 0.7rem;
}

.input-label {
  position: relative;
}

.label-span {
  position: absolute;
  top: 0;
  left: 1rem;
  transition: all 0.2s;
}

.input-label {
  font-size: 0.9rem;
}

.input:focus + .label-span,
.input:valid + .label-span {
  top: -1.5rem;
  left: 0.5rem;
  font-size: 0.9rem;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <div class="input-container">
      <label class="input-label" for="#">
        <input class="input js_form-input" type="text" required />
        <span class="label-span">First Name</span>
      </label>
    </div>

    <div class="input-container">
      <label class="input-label" for="#">
        <input class="input js_form-input" type="text" required/>
        <span class="label-span">Surname</span>
      </label>
    </div>

    <div class="input-container">
      <label class="input-label" for="#">
        <input class="input js_form-input" type="text" required/>
        <span class="label-span">Email</span>
      </label>
    </div>
  </body>
</html>

Upvotes: 0

Kumar Gaurav
Kumar Gaurav

Reputation: 738

I hope, This will solve your problem.

var myform = document.querySelectorAll(".input-label");

        Array.from(myform).map(x => {
            x.addEventListener('change', (e) => {
                var el = e.target.parentNode.children[1];
                if (e.target.value !== "") {
                    el.style.top = "-1.5rem";
                } else {
                    el.style.top = "0rem";
                }
            });
        });
* {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: Arial, Helvetica, sans-serif;
        }

        .input-container {
            padding: 20px;
        }

        .input {
            width: 100%;
            border: 0;
            border-bottom: solid 1px grey;
            padding-left: 1rem;
            margin-bottom: 2rem;
            color: #000;
            padding-bottom: 0.7rem;
        }

        .input-label {
            position: relative;
        }

        .label-span {
            position: absolute;
            top: 0;
            left: 1rem;
            transition: all 0.2s;
        }

        .input-label {
            font-size: 0.9rem;
        }

        .input:focus+.label-span {
            top: -1.5rem;
            left: 0.5rem;
            font-size: 0.7rem;
        }
<div class="input-container">
            <label class="input-label" for="#">
                <input class="input js_form-input" type="text" />
                <span class="label-span">First Name</span>
            </label>
        </div>

        <div class="input-container">
            <label class="input-label" for="#">
                <input class="input js_form-input" type="text" />
                <span class="label-span">Surname</span>
            </label>
        </div>

        <div class="input-container">
            <label class="input-label" for="#">
                <input class="input js_form-input" type="text" />
                <span class="label-span">Email</span>
            </label>
        </div>

Upvotes: 1

pilchard
pilchard

Reputation: 12919

Your CSS is sufficient to get the affect you are after, just remove the javascript. The only problem that I fixed is adding pointer-events: none; to the .label-span elements as they were blocking focus when clicking on them.

Edited to include a check on blur for whether the input is empty or not and maintain the label position if it is full.

const inputs = document.querySelectorAll('.js_form-input');

inputs.forEach(input => {
    input.addEventListener('blur', (event) => {
    if (event.target.value.length) {
        event.target.classList.add("full");
    } else {
        event.target.classList.remove("full");
    }
});
})
#container {
  padding: 2rem 0;
}

.input {
  width: 100%;
  border: 0;
  border-bottom: solid 1px grey;
  padding-left: 1rem;
  margin-bottom: 2rem;
  color: $c_pop;
  padding-bottom: 0.7rem;
}

.input-label {
  position: relative;
}

.label-span {
  position: absolute;
  top: 0;
  left: 1rem;
  transition: all 0.2s;
  pointer-events: none;
}

.input-label {
  font-size: 0.9rem;
}

.input:focus+.label-span, .input.full+.label-span {
  top: -1.5rem;
  left: 0.5rem;
  font-size: 0.7rem;
}
<div id="container">
  <div class="input-container">
    <label class="input-label" for="#">
      <input class="input js_form-input" type="text">
      <span class="label-span">First Name</span>
    </label>
  </div>

  <div class="input-container">
    <label class="input-label" for="#">
      <input class="input js_form-input" type="text">
      <span class="label-span">Surname</span>
    </label>
  </div>

  <div class="input-container">
    <label class="input-label" for="#">
      <input class="input js_form-input" type="text">
      <span class="label-span">Email</span>
    </label>
  </div>
</div>

Upvotes: 2

Related Questions