JSFiddle - React, Tailwind, and code Playground

by Annett

HTML

<label class="input">
  <span>Email address</span>
  <input type="text" />
</label>

<div class="mktoFieldWrap mktoRequiredField"><label for="FirstName" class="mktoLabel mktoHasWidth" style="width: 120px;"><div class="mktoAsterix">*</div>First Name:</label><div class="mktoGutter mktoHasWidth" style="width: 10px;"></div><input id="FirstName" name="FirstName" maxlength="255" type="text" class="mktoField mktoTextField mktoHasWidth mktoRequired" style="width: 150px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABHklEQVQ4EaVTO26DQBD1ohQWaS2lg9JybZ+AK7hNwx2oIoVf4UPQ0Lj1FdKktevIpel8AKNUkDcWMxpgSaIEaTVv3sx7uztiTdu2s/98DywOw3Dued4Who/M2aIx5lZV1aEsy0+qiwHELyi+Ytl0PQ69SxAxkWIA4RMRTdNsKE59juMcuZd6xIAFeZ6fGCdJ8kY4y7KAuTRNGd7jyEBXsdOPE3a0QGPsniOnnYMO67LgSQN9T41F2QGrQRRFCwyzoIF2qyBuKKbcOgPXdVeY9rMWgNsjf9ccYesJhk3f5dYT1HX9gR0LLQR30TnjkUEcx2uIuS4RnI+aj6sJR0AM8AaumPaM/rRehyWhXqbFAA9kh3/8/NvHxAYGAsZ/il8IalkCLBfNVAAAAABJRU5ErkJggg==); background-attachment: scroll; background-position: 100% 50%; background-repeat: no-repeat;"><div class="mktoClear"></div></div>

CSS

.input {
  display: block;
}
.input span {
  position: absolute;
  z-index: 1;
  cursor: text;
  pointer-events: none;
  color: #999;
  /* Input padding + input border */
  padding: 7px;
  /* Firefox does not respond well to different line heights. Use padding instead. */
  line-height: 17px;
  /* This gives a little gap between the cursor and the label */
  margin-left: 2px;
}
.input input, .input textarea, .input select {
  z-index: 0;
  padding: 6px;
  margin: 0;
  font: inherit;
  line-height: 17px;
}
.input select {
  padding: 5px;
  /* Unfortunately selects don't respond well to padding. They need an explicit height. */
  height: 31px;
}

JavaScript

(function($) {

  function measureWidth(deflt) {
    var dummy = $('<label></label>').text(deflt).css('visibility','hidden').appendTo(document.body);
    var result = dummy.width();
    dummy.remove();
    return result;
  }

  function toggleLabel() {
    var input = $(this);
    var deflt = input.attr('title');
    var span = input.prev('span');
    setTimeout(function() {
      if (!input.val() || (input.val() == deflt)) {
        span.css('visibility', '');
        if (deflt) {
          span.css('margin-left', measureWidth(deflt) + 2 + 'px');
        }
      } else {
        span.css('visibility', 'hidden');
      }
    }, 0);
  };

  $(document).on('cut', 'input, textarea', toggleLabel);
  $(document).on('keydown', 'input, textarea', toggleLabel);
  $(document).on('paste', 'input, textarea', toggleLabel);
  $(document).on('change', 'select', toggleLabel);

  $(document).on('focusin', 'input, textarea', function() {
      $(this).prev('span').css('color', '#ccc');
  });
  $(document).on('focusout', 'input, textarea', function() {
      $(this).prev('span').css('color', '#999');
  });

  function init() {
    $('input, textarea, select').each(toggleLabel);
  };

  // Set things up as soon as the DOM is ready.
  $(init);

  // Do it again to detect Chrome autofill.
  $(window).load(function() {
    setTimeout(init, 0);
  });

})(jQuery);