header.c-banner
div.c-container
        .c-contact
            h1 We'd love to hear from you.
            p Have a question about us? Need to talk to customer service? Have a great idea? Drop us a line and we'll get back to you as soon as we can.
            p Have an urgent problem about an order? Call our warehouse at 1234-1234.
            p We can also get in touch on 
                a(href="https://www.twitter.com/" target="_blank") Twitter
                | .
        form.c-form#form
            label(for="email")
                span.c-form-label Email 
                     abbr(title="Required") *
                input.c-form-input#form-email(type="email", name="email" required='required' pattern=".{3,}")
                span.u-alert#form-email-error Please enter a valid email format
            label(for="name")
                span.c-form-label Name
                input.c-form-input#form-name(type="text", name="name" pattern="^[A-Za-z ,.'-]+$")
                span.u-alert#form-name-error Please enter a valid name with alphabets only
            label(for="message")
                span.c-form-label Message 
                     abbr(title="Required") *
                textarea.c-form-input#form-message(minlength="10", maxlength="200",rows="4", name="message", required='required')
                span.c-form-input__length
                    span#form-message-length 0
                    | /200
                span.u-alert#form-message-error Please enter at least 10 characters and less than 200 characters.
            label(for="signup").c-form-group
                input.c-form-checkbox#form-signup(type="checkbox", name="signup")
                span.c-form-label Sign me up for latest updates
            input.c-form-submit#form-submit(type="submit", value="Submit", name="submit")
            span.u-alert#form-submit-error Please correct all information and try again.
        div.c-thankyou.u-hide#form-thankyou
            h1 Thank you!
            p We will contact you as soon as possible.
footer
        p Page design from 
            a(href="https://uigarage.net/boka-contact-form/" target="_blank") Boka Contact Form
View Compiled
//text color
$text: #7E7E7E
$alert: #EF5350
$btn: #FB9375
$btn-hover: #FB9375

$theme: #FF9473

//mobile query based on bootstrap
$phone: "only screen and (min-width : 576px)"
$tablet: "only screen and (min-width : 768px)"
$laptop: "only screen and (min-width : 992px)"
$desktop: "only screen and (min-width : 1200px)"

body
  font-family: 'Lato', sans-serif
  margin: 0
  padding: 0
  width: 100%
  height: 100%
  line-height: 1.48
  color: $text

*
  box-sizing: border-box

h1,h2,h3
  font-family: 'Roboto', sans-serif
  color: $text

h1
  font-size: 1.8em
  margin-bottom: 0.8em

a,
a:visited,
a:focus,
a:active
  color: $text

.c-banner
  position: relative
  height: 18em
  background-image: url('//snowleo208.github.io/100-Days-of-Code/instant-form-validation/giulia-bertelli-116358-unsplash.jpg')
  background-size: cover
  background-repeat: no-repeat
  background-position: 50% 60%
  border-bottom: solid 5px $theme
  @media #{$laptop}
    height: 20em
  
  &:before
    content: ''
    position: absolute
    bottom: -1.2em
    left: calc((100% - 2.4em) / 2)
    width: 0
    height: 0
    border-style: solid
    border-width: 1.2em 1.2em 0 1.2em
    border-color: $theme transparent transparent transparent
    @media #{$laptop}
      left: calc((100% - 2.4em) / 2)

.c-container
  display: flex
  flex-direction: column
  max-width: 960px
  margin: 0 auto
  padding: 1em
  margin-bottom: 2em
  @media #{$laptop}
    flex-direction: row
    padding: 3em
    margin-bottom: 4em

  h1
    position: relative
    text-transform: uppercase
    font-size: 1.4em
    letter-spacing: 0.1em
    color: #686A66
    &:before
      content: ''
      position: absolute
      width: 10%
      height: 5px
      bottom: -0.5em
      left: 0
      background: $btn

.c-contact
  display: flex
  flex-direction: column
  align-items: flex-start
  justify-content: center
  padding: 1em 0
  @media #{$laptop}
    max-width: 50%
    border-right: solid 3px #F8BD55
    padding: 2em
  
  h1
    margin: 0 0 1.5em 0

  p
    margin-top: 0
    margin-bottom: 1em
    color: #7E7E7E
  
.c-form
  max-width: 500px
  margin: 0
  @media #{$laptop}
    padding: 1em
    margin: 0 auto

  label
    margin-bottom: 1em

.c-form-group
  display: flex
  align-items: center
  justify-content: flex-start
  margin: 0.8em 0 1em 0

label[for="email"] > .c-form-label
    margin: 0 0 0.2em 0

.c-form-label
  display: block
  margin: 1em 0 0.2em 0
  font-size: 0.8em
  text-transform: uppercase
  color: rgba(25,25,25,0.8)
  abbr
    color: $alert
    text-decoration: none

  
.c-form-input
  display: block
  border-color: rgba(25,25,25,0.1)
  border-width: 0 0 2px 0
  padding: 0.2em 2em 0.2em 0
  // margin-bottom: 1em
  transition: border-color ease 300ms
  background-repeat: no-repeat
  background-size: 20px 20px
  background-position: 99% 50%
  width: 100%
  &:focus
    border-color: #03A9F4
  &[aria-invalid="false"]
    //invalid
    background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%234CAF50' d='M9.984 17.016l9-9-1.406-1.453-7.594 7.594-3.563-3.563-1.406 1.406zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
    margin-bottom: 0

  &[aria-invalid="true"]
      //valid
    background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%23F44336' d='M17.016 15.609l-3.609-3.609 3.609-3.609-1.406-1.406-3.609 3.609-3.609-3.609-1.406 1.406 3.609 3.609-3.609 3.609 1.406 1.406 3.609-3.609 3.609 3.609zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
    border-color: $alert
    margin-bottom: 0
  
  &__length
    font-size: 0.7em
    color: #757575
    float: right
    clear: both
    margin-top: 0.2em

textarea.c-form-input
  background-position: 99% 0

  &[aria-invalid="false"]
    //invalid
    background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%234CAF50' d='M9.984 17.016l9-9-1.406-1.453-7.594 7.594-3.563-3.563-1.406 1.406zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
    margin-bottom: 0

  &[aria-invalid="true"]
      //valid
    background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%23F44336' d='M17.016 15.609l-3.609-3.609 3.609-3.609-1.406-1.406-3.609 3.609-3.609-3.609-1.406 1.406 3.609 3.609-3.609 3.609 1.406 1.406 3.609-3.609 3.609 3.609zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
    border-color: $alert

.c-form-checkbox
  appearance: none
  -webkit-appearance: none
  width: 1em
  height: 1em
  border: solid $text 2px
  margin-right: 0.2em
  border-color: #efefef
  transition: ease 400ms
  background-size: 0 0
  cursor: pointer
  &:checked
    background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%23FB9375' d='M9 16.172l10.594-10.594 1.406 1.406-12 12-5.578-5.578 1.406-1.406z'></path></svg>")
    background-size: 20px 20px
    background-position: 50% 50%
    background-repeat: no-repeat


  & + .c-form-label
    margin: 0
  
.c-form-submit
  background-color: $btn
  font-size: 0.8em
  font-weight: bold
  letter-spacing: 0.1em
  color: white
  border: 0
  padding: 0.5em 1em
  margin-top: 1em
  cursor: pointer
  transition: ease 400ms
  text-align: center
  text-transform: uppercase
  &:hover
    opacity: 0.9

.c-thankyou
  padding: 1em 0
  opacity: 1
  animation: fade 600ms forwards

  @media #{$laptop}
    padding: 2em
  &.u-hide
    animation: none

footer
  p
    font-size: 0.8em
    text-align: center
    padding: 0.7em
  
.u-alert
  display: block
  height: 0
  opacity: 0
  height: 0
  overflow: hidden
  transition: ease 400ms
  font-size: 0.8em
  &.invalid
    color: $alert
    opacity: 1
    height: auto
    max-height: none
    margin-top: 0.3em

.u-hide
  display: none

@keyframes fade
  0%
    opacity: 0
  100%
    opacity: 1
View Compiled
(() => {

  let timer; //timer for requestAnimationFrame in debounce func
  let length = 0; //text length for message field

  const inputList = Array.prototype.slice.call(document.getElementsByTagName('input')).filter(item => item.type !== 'submit' && item.type !== 'checkbox');
  const input = inputList.concat(Array.prototype.slice.call(document.getElementsByTagName('textarea')));


  //valid each item and set error message
  function isValid(input) {
    const target = input.id ? input.id : input.target.id;
    const valid = document.getElementById(target).validity.valid;
    if (valid) {
      document.getElementById(`${target}-error`).classList.remove('invalid');
      document.getElementById(`${target}-error`).removeAttribute('role');
      document.getElementById(target).setAttribute('aria-invalid', 'false');
    } else {
      document.getElementById(`${target}-error`).classList.add('invalid');
      document.getElementById(`${target}-error`).setAttribute('role', 'alert');
      document.getElementById(target).setAttribute('aria-invalid', 'true');
      console.log(document.getElementById(target));
    }

    if (document.getElementById('form-message').value.length !== length) {
      length = document.getElementById('form-message').value.length;
      document.getElementById('form-message-length').innerText = length;
    }

    return valid;
  }

  //valid all items and return all are valid or not
  function validAll(arr) {
    let count = 0;
    console.log(typeof arr);
    if (typeof arr !== 'object') {
      return isValid(arr);
    } else {
      arr.forEach(function (ele) {
        if (isValid(ele)) {
          count++;
        }
      });
    }

    return count === arr.length;
  }

  function formSubmit(e) {
    e.preventDefault();

    if (validAll(input)) {
      console.log('valid');
      document.getElementById('form-submit-error').classList.remove('invalid');

      //show thank you message after submission
      document.getElementById('form').classList.add('u-hide');
      document.getElementById('form-thankyou').classList.remove('u-hide');
    } else {
      console.log('invalid');
      document.getElementById('form-submit-error').classList.add('invalid');
    }

  }

  //debounce func using RAF
  function debounce(e = null, func) {
    const raf = requestAnimationFrame || mozRequestAnimationFrame ||
      webkitRequestAnimationFrame || msRequestAnimationFrame;

    const caf = window.cancelAnimationFrame || window.mozCancelAnimationFrame;

    if (timer) {
      timer = caf(timer);
    }

    timer = raf(function (timestamp) {
      func(e);
      return timestamp;
    })

  }

  (() => {
    //custom event polyfill for checking autocomplete / prefill input in IE11 from MDN
    (function () {

      if (typeof window.CustomEvent === "function") return false;

      function CustomEvent(event, params) {
        params = params || {
          bubbles: false,
          cancelable: false,
          detail: undefined
        };
        var evt = document.createEvent('CustomEvent');
        evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
        return evt;
      }

      CustomEvent.prototype = window.Event.prototype;

      window.CustomEvent = CustomEvent;
    })();


    input.forEach(item => {
      if (item.type !== 'submit' && item.type !== 'checkbox') {

        //add event listener for input
        item.addEventListener('input', function (e) {
          debounce(e, isValid)
        })

        if (item.value !== '') {
          //if input is already prefilled, check its validity
          const initCheck = new CustomEvent('initial');
          item.addEventListener('initial', isValid);
          item.dispatchEvent(initCheck);
        } else {
          //remove attribute label to hide visual warning, like red border or red icons, as it is not prefilled
          item.removeAttribute('aria-invalid');
        }
      }
    })

    document.getElementById('form-submit').addEventListener('click', formSubmit);

  })();

})();
View Compiled

External CSS

  1. https://fonts.googleapis.com/css?family=Roboto|Lato

External JavaScript

This Pen doesn't use any external JavaScript resources.