DEV Community

Felix Guerin
Felix Guerin

Posted on

Floating input placeholders with HTML/CSS

Here is a cool way to make the placeholders "become" labels as the input receives focus.

Here is a pen with the final result.

First, you have to put the label AFTER the input in the HTML.

<form action="">
  <input type="text" id="fullName" name="fullName">
  <label for="fullName">Full Name</label>
</form>

This will ensure that we can target the label with our CSS.

Then, instead of giving the input a placeholder directly in the HTML, we will use our label as the placeholder. In order for the label to be inside the input, we can use transform: translate(). We can also use a lighter color to really make it look like a native placeholder.

Here is the relevant CSS for the initial state (the values used for the translation can vary depending on font size, positioning, etc.).

    label {
      color: #999;
      transform: translate(0.25rem, -1.5rem);
      transition: all 0.2s ease-out;
    }

Now, to position it on top of the text when the input is in focus, use the following.

    input:focus + label {
      color: #111;
      transform: translate(0, -2.75rem);
    }

It works!

But we still have a problem. The styles are are only applied to the label when the input is in focus. This means that if you type something in the input then focus elsewhere, the label will come back to it's original position.

To fix this, we will have to use the :placeholder-shown selector. This selector allows to style an element whenever an input's placeholder is, well, shown. In our case, we actually want to style the label when the placeholder is NOT shown, so we will also have to use the :not() selector. Finally, for this to work, your input has to have a placeholder. Since we want to use our label as the placeholder text, we can simply write an empty space as the placeholder value (an empty string "" will not work).

<form action="">
  <input type="text" id="fullName" name="fullName" placeholder=" ">
  <label for="fullName">Full Name</label>
</form>
    input:focus + label,
    input:not(:placeholder-shown) + label  {
      color: #111;
      transform: translate(0, -2.75rem);
    }

Now everything works like we want it to.

The :placeholder-shown selector is relatively new, but browser support is pretty good. The only browser to not recognize it is Edge. To remedy this, we can use a @supports query hack to check if the code is run in Edge (you can find more hacks like this at http://browserhacks.com/).

Usually, this hack is used write code that is only supported in Edge. Since we want the opposite, we can add not in front of the condition of the query.

We should also apply the final position to the label before anything else. This way, the Edge browser will display the labels on top of the inputs like a normal form, and the other browsers will apply the 'placeholder' styling to it.

label {
  display: block;
  transform: translate(0, -2.75rem);
}

@supports (not (-ms-ime-align:auto)) {
    label {
      color: #999;
      transform: translate(0.25rem, -1.5rem);
      transition: all 0.2s ease-out;
    }

    input:focus + label,
    input:not(:placeholder-shown) + label {
      color: #111;
      transform: translate(0, -2.75rem);
    }
}

Another possibility for this cool form style is to only move the label when a user types something. For this, you can simply remove the input:focus + label selector. Here is the result.

I hope you found this useful! Let me know in the comments.

Discussion (2)

Collapse
eugenman profile image
Eugen

Real hack without js. Thanks.

Collapse
titanhero profile image
Lex

Very cool...animus..Peace && Love