Table of Contents

Contact Form

  • Message can not be empty.

About

This contact form is inspired from the one that I designed for Cure interactive's website, with a more interactive message input and improved CSS styling.

The Code

HTML

<section class="contact_form">
    <h1>Contact Form</h1>
    <div class="row">
      <div id="contact_form__info" class="col-phone-12 col-tablet-5 col-desktop-small-4">
        <table>
          <tr>
            <td><strong>Phone:</strong><br><span>Recipient:</span></td>
            <td><em><a href="tel://1-###-###-####">+1 (###) ###-####</a><br><span>James Steele Seeley</span></em></td>
          </tr>
          <tr>
            <td><strong>Location:</strong></td>
            <td><em><b><address><a href="https://www.google.com/maps/place/221B+Baker+St,+Marylebone,+London+NW1+6XE,+UK/@51.523767,-0.1585557,17z/data=!3m1!4b1!4m5!3m4!1s0x48761acf33628211:0x445d7677a88322e1!8m2!3d51.523767!4d-0.1585557?hl=en">221b Baker St,<br>Marylebone,<br>London NW1 6XE,<br>United Kingdom</a></address></b></em></td>
          </tr>
          <tr>
            <td id="contact_form__map" colspan="2">
              <iframe id="preview" style="border: 0px none; width: 100%; height: 100%;" src="https://www.google.com/maps/embed/v1/search?q=%20221B%20Baker%20St%2C%20Marylebone%2C%20London&amp;key=AIzaSyBFw0Qbyq9zTFTd-tUY6dZWTgaQzuU17R8" frameborder="0"></iframe>
            </td>
          </tr>
          <tr>
            <td><strong>Social:</strong></td>
            <td class="box-social">
              <a href="https://www.facebook.com/FacebookAccount" onclick="return false;" style="color:#3b5998 !important;">Facebook <span class="icon-social-facebook"></span></a>
              <br>
              <a href="https://twitter.com/twitteraccount" onclick="return false;" style="color:#55acee !important;">Twitter <span class="icon-social-twitter"></span></a>
              <br>
              <a href="https://www.youtube.com/user/account/videos" onclick="return false;" style="color:#cd201f !important;">YouTube <span class="icon-social-youtube"></span></a>
            </td>
          </tr>
        </table>
      </div>
      <div class="col-phone-12 col-tablet-7 col-desktop-small-8">
        <div id="contact_form__message">
          <textarea id="contact_form__message__input" name="name" style="height:310px" placeholder='Enter and send us a message.'></textarea>
          <div id="contact_form__message__process" class="disabled">
            <div id="contact_form__message__process__anim">
              <img class="retina1x" src="/image/interface/loading/001_light_64px.gif" alt="">
              <img class="retina2x" src="/image/interface/loading/001_light_128px.gif" alt="">
            </div>
          </div>
        </div>
        <button id="contact_form__message__submit" type="button" name="button">Send Message</button>
        <ul id="contact_form__message__notice">
          <li id="contact_form__message__notice__empty">Message can not be empty.</li>
        </ul>
      </div>
    </div>
  </section>

CSS

.contact_form {
  overflow-x: auto;
}

.contact_form table {
  table-layout: auto;
  width: 100%;
}

.contact_form table tr * {
  word-break: normal;
}

.contact_form table tr td {
  vertical-align: middle;
}

.contact_form table tr:first-child td span {
  font-size: 0.7em;
  font-weight: bold;
}

.contact_form table tr td:nth-child(1) {
  text-align: left;
  padding-right: 5px;
}

.contact_form table tr td:nth-child(2) {
  text-align: right;
}

tbody .contact_form table tr:not(:last-child) td {
  padding-bottom: 10px;
}

tbody .contact_form table tr:last-child td {
  padding-top: 10px;
}

.contact_form table h6 {
  opacity: 0.5;
}

.no-touchevents .contact_form {
  background-image: url("/image/interface/contact/contact_background.png");
  background-position: left center;
  background-repeat: repeat-x;
  background-size: 1484px;
  -webkit-animation: contact_form-animation 45s linear infinite;
  -moz-animation: contact_form-animation 45s linear infinite;
  -ms-animation: contact_form-animation 45s linear infinite;
  -o-animation: contact_form-animation 45s linear infinite;
  animation: contact_form-animation 45s linear infinite;
}

#contact_form__map {
  background-color: #e5e3df;
  height: 150px;
  line-height: 100%;
  width: 100%;
  background-size: contain;
  padding: 0px;
  text-align: center;
  position: relative;
}

#contact_form__map:before,#contact_form__map:after {
  position: absolute;
}

#contact_form__map:after {
  content: '';
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: black;
  opacity: 0.1875;
  z-index: 2;
  pointer-events: none;
}

#contact_form__map:before {
  content: "Map Here";
  color: black;
  top: 50%;
  left: 50%;
  -webkit-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

#contact_form__map iframe {
  z-index: 1;
  position: absolute;
  top: 0;
}

@-webkit-keyframes contact_form-animation {
  from {
    background-position-x: 0px;
  }

  to {
    background-position-x: -1484px;
  }
}

@keyframes contact_form-animation {
  from {
    background-position-x: 0px;
  }

  to {
    background-position-x: -1484px;
  }
}

#contact_form__message {
  position: relative;
}

#contact_form__message #contact_form__message__input {
  resize: vertical;
  margin-bottom: 0px;
}

#contact_form__message #contact_form__message__process {
  display: none;
  background-color: rgba(0,0,0,0.5);
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin-top: 0px;
  opacity: 1;
  pointer-events: none;
}

#contact_form__message #contact_form__message__process__anim {
  position: absolute;
  top: 50%;
  left: 50%;
  -webkit-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

#contact_form__message #contact_form__message__process__anim:after {
  display: inline-block;
  font-weight: bold;
  font-size: 1.25em;
}

#contact_form__message #contact_form__message__process__anim img {
  margin-bottom: 0px;
  max-width: 64px;
  max-height: 64px;
  opacity: 0.825;
  -webkit-filter: invert(100%);
  filter: invert(100%);
}

#contact_form__message #contact_form__message__process__anim img.retina1x {
  display: block;
}

#contact_form__message #contact_form__message__process__anim img.retina2x {
  display: none;
}

#contact_form__message.contact_form__message--processing #contact_form__message__process,#contact_form__message.contact_form__message--processed #contact_form__message__process {
  display: block;
}

#contact_form__message.contact_form__message--processing #contact_form__message__process__anim:after {
  content: 'Sending Message';
  margin-top: 1em;
}

#contact_form__message.contact_form__message--processed #contact_form__message__process__anim:after {
  content: 'Message Sent';
  font-size: 1.5em;
}

#contact_form__message.contact_form__message--processed #contact_form__message__process__anim img {
  display: none;
}

#contact_form__message__notice {
  color: #F44;
  display: inline-block;
  float: left;
  margin-bottom: 0px;
  margin-top: 0px;
  float: right;
  margin-right: 1em;
}

#contact_form__message__notice li::marker {
  content: '*';
}

#contact_form__message__submit {
  margin: 0;
  float: right;
}

.box-social {
  font-size: 1.1em;
}

.no-touchevents .social-box:hover {
  opacity: 0.5;
}

html:not(.touchscrolled) .social-box:active,.no-touchevents .social-box:active {
  opacity: 0.25;
}

@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi), (min-resolution: 2dppx) {
  #contact_form__message__process #contact_form__message__process__anim img.retina1x {
    display: none;
  }

  #contact_form__message__process #contact_form__message__process__anim img.retina2x {
    display: block;
  }
}

JavaScript

// =============================================================================
  // events.js

  function addEvent(evnts, elems, func) {
    var evntLength = 1;
    if ( evnts instanceof Array ) evntLength = evnts.length;

    var elemLength = elems.length || 1;
    if ( elems instanceof Array ) elemLength = elems.length;

    for (var i = 0; i < evntLength; i++) {
      var evnt = evntLength == 1 ? evnts : evnts[i];

      for (var i = 0; i < elemLength; i++) {
        var elem = elemLength == 1 ? ( NodeList.prototype.isPrototypeOf(elems) ? elems[0] : elems ) : elems[i];

        if (elem.addEventListener) { // W3C DOM
          elem.addEventListener(evnt, func, false);
        }
        else if (elem.attachEvent) { // IE DOM
          elem.attachEvent('on' + evnt, func);
        }
        else { // No much to do
          elem['on' + evnt] = func;
        }
      }
    }
  }

  // =============================================================================
  // classes.js

  /**
   * Returns whether the given element has the given class.
   *
   * @param {Element} element
   * @param {string} className
   * @returns {boolean}
   */
  function hasClass(element, className) {
  	className = ' ' + className + ' ';
  	return (' ' + element.className + ' ').replace(/[\n\t]/g, ' ').indexOf(className) > -1
  }

  function addClass(elements, className) {
    if ( elements.length === undefined ) elements = [elements];
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      if (!hasClass(element, className)) {
        if (element.classList) {
          element.classList.add(className);
        } else {
          element.className = ( element.className + ' ' + className ).replace( /\s+/g, ' ');
        }
      }
    }
  }

  function removeClass(elements, className) {
    if ( elements.length === undefined ) elements = [ elements ];
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      if (hasClass(element, className)) {
        if (element.classList) {
          element.classList.remove(className);
        } else {
          element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
        }
      }
    }
  }

  // =============================================================================
  // properties.js

  function getStyle(el) {
    return window.getComputedStyle ? getComputedStyle(el, null) : el.currentStyle;
  }

  // =============================================================================
  // contact_form.js

  var contact_form__info = document.getElementById('contact_form__info');
  var contact_form__message__input = document.getElementById('contact_form__message__input');
  var contact_form__message = document.getElementById('contact_form__message');
  var contact_form__message__notice__empty = document.getElementById('contact_form__message__notice__empty');
  var contact_form__message__submit = document.getElementById('contact_form__message__submit');

  // height update

  function updateheights() {
    contact_form__message__input.style.minHeight = ( parseFloat( getStyle( contact_form__info ).height) - 80 ) + 'px';
  }

  var contactTimeout = [];

  addEvent( 'resize', window, function(event) {
    for ( var i = 0; i < 100; i++ ) {
      if ( contactTimeout[ i ] !== 'undefined' ) clearTimeout( contactTimeout[ i ] );
      contactTimeout[ i ] = setTimeout( updateheights, i * 10 );
    }
  } );

  updateheights();

  // message interface

  function initDisabledShake( event ) {
    document.dispatchEvent( new CustomEvent( "updateDisabledShake", { detail: {
      event: event, // not optional, needed to access the parent event in the custom event
      force: true // will not check for disabled inputs before adding disabled events
    } } ) );
  }

  function updateSendButton() {
    if ( contact_form__message__input.value )
    {
      contact_form__message__submit.removeAttribute('disabled');
      contact_form__message__notice__empty.style.display = 'none';
    }
    else
    {
      contact_form__message__submit.disabled = 'disabled';
      contact_form__message__notice__empty.style.display = '';
      initDisabledShake();
    }
  }

  addEvent( 'keyup', contact_form__message__input, function( event ) {
    updateSendButton();
  } );

  function sendMessage( event ) {
    contact_form__message__input.disabled = 'disabled';
    addClass( contact_form__message, 'contact_form__message--processing' );
    initDisabledShake( event );

    setTimeout( function() {
      contact_form__message__submit.disabled = 'disabled';
      initDisabledShake( event );
    }, 250 );

    setTimeout( function() {
      contact_form__message__input.value = ' ';
      removeClass( contact_form__message, 'contact_form__message--processing' );
      addClass( contact_form__message, 'contact_form__message--processed' );
    }, 3000 );

    setTimeout( function() {
      contact_form__message__input.value = '';
      contact_form__message__input.removeAttribute('disabled');
      removeClass( contact_form__message, 'contact_form__message--processed' );
      updateSendButton();
    }, 6000 );
  }

  addEvent( 'click', contact_form__message__submit, function( event ) {
    sendMessage( event );
  } );

  function initMessageInterface() {
    updateSendButton();
    initDisabledShake();
  }

  initMessageInterface();