Input with immediate feedback

by Konstantin Rouda

HTML

<form method="POST">
<div class="input-container">
  <input type="text" name="name" id="name" maxlength="40" class="input">
  <label class="indicator"></label>
  <label for="name" class="input-label">name</label>
  <label class="error-label">this field is required</label>
</div>

<div class="input-container">
  <button type="submit" class="submit-btn">submit</button>
</div>
</form>

CSS

BODY {
  background: #fff;
  font-family: Helvetica;
  font-size: 16px;
}

FORM {
  max-width: 800px;
  margin: 1em auto 0;
  padding: 1em;
}

.input-container {
    position: relative;
    text-align: center;
    padding: 1em 1px;
    margin-bottom: 2em;
    overflow: hidden;
    border-radius: 0.3125em;
}

.indicator:before {
    content: "";
    position: absolute;
    top: .75em;
    left: .4em;
    width: 40px;
    height: 40px;
    color: #000;
    font-size: 1.8em;
    border-radius: 5px;
    display: none;
}

.input-container .input:focus + .indicator:before {
  display: block;
  content: "\27A4"; /*arrow sign*/
  background: #959595;
}

.input.valid + .indicator:before {
  content: "\2714";  /*V sign*/
  background: rgb(149, 193, 147);
  display: block;
}

.input.invalid + .indicator:before {
  content: "\2715";  /*X sign*/
  background: rgb(202, 70, 70);
  display: block;
}

.input {
    border: none;
    border-bottom: 2px solid #f3f3f3;
    width: 100%;
    transform: scale(.93);
    transform-origin: right;
    background: #e2e2e2;
    min-height: 50px;
    color: #000;
    font-weight: 600;
    letter-spacing: 1px;
    border-radius: 3px;
    outline: 0;
}

.input:focus {
    box-shadow: 0 0 0 5.5em rgba(0, 0, 0, .04);
}

.input-label {
    position: absolute;
    top: 0;
    left: 3.5em;
    -moz-transform: translate(0,.8em);
    -ms-transform: translate(0,.8em);
    -o-transform: translate(0,.8em);
    -webkit-transform: translate(0,.8em);
    transform: translate(0,.8em);
    font-size: 1.2em;
    color: #919191;
    -moz-transition: transform .3s ease;
    -o-transition: transform .3s ease;
    -webkit-transition: transform .3s ease;
    transition: transform .3s ease;
}

.input:focus ~ .input-label {
    font-size: 1.2em;
    -moz-transform: translate(0,-.15em);
    -ms-transform: translate(0,-.15em);
    -o-transform: translate(0,-.15em);
    -webkit-transform: translate(0,-.15em);
    transform: translate(0,-.15em);
    color: #989898;
   ...

JavaScript

/// By Konstantin Rouda
/// LinkedIn: https://il.linkedin.com/pub/konstantin-rouda/8a/2a9/262 
/// Twitter: https://twitter.com/KonstantinRouda

/// Inspired by sketch of Jakub Linowski  
//// https://www.instagram.com/p/BDEqJ_bS4AG/








/*simple 'required' validation*/

var inputs = document.getElementsByClassName("input");
var form = document.forms[0];
var canSendForm = false;

for(var i = 0, len = inputs.length; i < len; i++) {
		inputs[i].onblur = validateInput;
}

function validateInput(e) {
	var self = this;
  var inputVal = self.value.trim();
  var isInvalid = /\binvalid\b/.test(self.className);
  var isValid = /\bvalid\b/.test(self.className);
  
  if(inputVal === "" && !isInvalid) {
  		 removeClass(self, "valid");
       self.className += " invalid";
       canSendForm = false;
  } else if(inputVal !== "" && !isValid) {
  		 removeClass(self, "invalid");
  		 self.className += " valid";
       canSendForm = true;
  }
  		
};

function removeClass(elem, classToRemove) {
		var regExp = new RegExp("\\b" +  classToRemove + "\\b");
    elem.className = elem.className.replace(regExp, "").trim();
};

form.onsubmit = function(e) {
		var blurEvent;
    
    if(typeof window.Event === "function") {
    		blurEvent = new Event("blur");
    } else {
    		blurEvent = document.createEvent("Event");
        blurtEvent.initEvent("blur", true, true);
    }
    
    var triggerEventMethod = document.dispatchEvent ? "dispatchEvent" : "fireEvent";
    var formElements = this.elements;
    
    for(var i = 0, len = formElements.length; i < len; i++) {
				formElements[i][triggerEventMethod](blurEvent);
    }
    
    return canSendForm;
};