Animate placeholder for an input field event when user inputs something there

I’ve seen demos like this.

But it’s about creating a new element.

parent().append("<span>" + $input.attr('placeholder') + "</span>");

Is there a way to animate placeholder’s disappear on input event without appending a new element?

$("input[placeholder]").each(function () {
  var $input = $(this);
  // wrap the input with a label
  $input.wrap("<label class='placeholder'>");
  // append a span to the label
  $input.parent().append("<span>" + $input.attr('placeholder') + "</span>");
  // and finally remove the placeholder attribute
  $input.attr('placeholder', '');
}).keyup(function () {
  var $input = $(this);
  // toogle hidden class on span, according to whether there is content or not
  if ($input.val() === "") {
    $input.next("span").removeClass("hidden");
  } else {
    $input.next("span").addClass("hidden");
  }
});
label.placeholder {
  position: relative;
}

label.placeholder span {
  opacity: 1;
  -webkit-transition: opacity 250ms;
  -moz-transition: opacity 250ms;
  -o-transition: opacity 250ms;
  -ms-transition: opacity 250ms;
  transition: opacity 250ms;
  position: absolute;
  left: 5px;
  top: 2px;
  font-size: 12px;
  color: grey;
}

label.placeholder span.hidden {
  opacity: 0;
}
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <input type="text" placeholder="the placeholder">

solution

Is there a way to animate placeholder’s disappear on input event without appending a new element?

Since the default browser pseudo elements (i.e., ::-webkit-input-placeholder/::-moz-placeholder, :-ms-input-placeholder) are difficult to style across browsers, you could use a :before or :after pseudo element in place of the appended span element. However, since pseudo elements can’t be added to input elements, you would still need to wrap the input element.

Updated Example

The pseudo element is positioned absolutely relative to the parent so that it covers the parent element. The content value of the pseudo element is based on the wrapper element’s custom data-* attribute, data-placeholder, this is achieved using the content value attr(data-placeholder).

I also simplified your jQuery a little:

$('input[placeholder]').each(function () {
  $(this).wrap('<label class="placeholder" data-placeholder="' + this.placeholder + '">').attr('placeholder', '');
  }).on('keyup', function () {
  $(this).parent().toggleClass('hidden', this.value !== '');
});
label.placeholder {
  position: relative;
}
label.placeholder:after {
  content: attr(data-placeholder);
  position: absolute;
  top:0; right: 0;
  bottom: 0; left: 0;
  padding: 2px;
  font-size: 12px;
  color: grey;
  cursor: text;
  transition: opacity 250ms;
}
label.hidden.placeholder:after {
  opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" placeholder="the placeholder"/>

In case of long placeholder values, you could also add the following:

Updated Example

label.placeholder:after {
  /* .. */
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}