DEV Community


CSS-only floating label

・2 min read

One of those nifty things Google did with the Material Design guidelines is include floating labels. Don't know what a floating label is? Check it out:

Floating label GIF

Being the ever-curious sort that I am, I wondered if this could be accomplished sans JavaScript. Turn out, it can, but only for required fields.

Here's the demo:

(Note: as far as I know, CodePen embeds aren't yet supported on Please correct me if I'm wrong!)

To make this work, the markup has to be structured in a very specific way: the input has to be in front of the label. (Don't forget the for attribute on the label!)

In this example, I've given the label a class, form-control-placeholder, and made it absolutely positioned. The container, which holds the label and input, is set to be relatively positioned, so the label can act as an overlay to the input itself, appearing as the placeholder.

.form-group {
  position: relative;
  margin-bottom: 1.5rem;

.form-control-placeholder {
  position: absolute;
  top: 0;
  padding: 7px 0 0 13px;
  transition: all 200ms;
  opacity: 0.5;
Enter fullscreen mode Exit fullscreen mode

Then we add a style to move the label above the input when it (the input) has focus. This is why we put the input before the label; CSS only works in one direction (although changing this is on many a developer's wish list for CSS 4.0, including yours truly).

.form-control:focus + .form-control-placeholder {
  font-size: 75%;
  transform: translate3d(0, -100%, 0);
  opacity: 1;
Enter fullscreen mode Exit fullscreen mode

Unfortunately, this is not enough. As soon as the input loses focus, the label will shoop right down again, covering up the input, not caring at all about whether or not you just entered some text there. (Yes, in my head the label makes a "shoop" sound whenever it moves.)

There is no way to determine via CSS alone whether an input has something entered. The closest we can get is the :valid selector, which is only fulfilled on inputs that have the required parameter.

So, we update the CSS to include :valid:

.form-control:focus + .form-control-placeholder,
.form-control:valid + .form-control-placeholder {
  font-size: 75%;
  transform: translate3d(0, -100%, 0);
  opacity: 1;
Enter fullscreen mode Exit fullscreen mode

And now we have a working example of CSS-only floating labels. Unfortunately, there's no way to get around that required, um, requirement, without resorting to JavaScript.

This post was originally published on

Discussion (9)

ben profile image
Ben Halpern

You're correct about the lack of CodePen tag, will try to get it up soon.

gwillz profile image
gwillz • Edited

I believe there is a way to get around the required requirement.
Use .form-control:not(:placeholder-shown) + .form-control-placeholder.

On another note, :pseudo + .sibling doesn't work in IE or Edge.

peiche profile image
Paul Author

Since writing this, I have learned a lot about the :placeholder-shown pseudo-class. Thanks!

thesheebs profile image

...and placeholder-shown is experimental and does not work with IE or Edge.

gwillz profile image

It gets worse.

IE has :-ms-input-placeholder as a selector for :placeholder-shown and Edge does not.

Whereas Edge has ::-ms-input-placeholder as an element for ::placeholder and IE does not.

rpalo profile image
Ryan Palo

Shoop 👌🏻

lexlohr profile image
Alex Lohr

A small drawback is that you now can't use the form constraints API anymore to validate in the front-end.

mcheff profile image

Well done dude! This is perfect for what I was after!

davidshare profile image
David Itam Essien

This doesn't work for me.