6 Pure CSS1 with JSPublished 2026-10-05Free · no sign-up
Seven floating label fields where the label starts inside the field and moves up when you type: a classic version, an outlined field with a notch, a minimal underline, a filled field, a textarea, a select and a field that shows its error only after you have interacted with it.
The label sits inside the empty field and moves up and shrinks when the field is focused or filled. The input carries placeholder=" " so :placeholder-shown tells the CSS whether it is empty; the label is still a real label element linked with for and id.
In the outlined style the label floats onto the border and a background patch behind it cuts a notch in the outline. The patch colour must match the page, which is the one limitation; the other demos avoid it if your background varies.
A minimal field with only a bottom border. On focus a coloured bar grows from the centre across the underline, and the label floats up. The bar is a sibling span scaled with transform, so it animates smoothly without changing the layout.
The filled style gives the field a tinted background and a bottom border only, which makes it easy to spot on a busy page. The label floats within the fill, so there is no notch to worry about and any page background works.
The same technique works on a textarea: placeholder=" " plus :placeholder-shown. The label floats to the top edge, and a solid background behind it keeps it readable once the text scrolls underneath.
A select has no placeholder, so the label floats when the select is :valid. The first option is an empty, disabled prompt and the select is required, which makes it invalid until something real is chosen.
Errors show only after the person has interacted with the field, using :user-invalid, so nobody sees red before typing. The error text is linked with aria-describedby and the input gets aria-invalid from a few lines of script, keeping the state available to screen readers.
var i = document.getElementById('fl7u');
['input', 'blur'].forEach(function (ev) { i.addEventListener(ev, function () { if (ev === 'blur' || i.getAttribute('aria-invalid')) i.setAttribute('aria-invalid', !i.checkValidity()); }); });
About these CSS Floating Label Inputs
The placeholder trick
CSS cannot tell whether an input has a value, but it can tell whether its placeholder is showing. Give the input placeholder=" " (a single space) and use :not(:placeholder-shown) to float the label once something is typed.
Keep a real label
The floating text must be a <label> linked to the input with for and id, not a placeholder. Placeholders vanish when typing starts and are often too pale to read.
Selects float when valid
A select has no placeholder. Make the first option empty and disabled and the select required; it is then :invalid until a real choice is made, and :valid floats the label.
Errors after interaction
:user-invalid only matches once the person has edited or left a field, so nobody sees red on page load. Link the hint with aria-describedby and set aria-invalid so the error is announced.
Frequently asked questions
Do floating labels hurt usability?
The label stays visible at all times, which is the main thing. Keep the floated label large enough to read, at least 12px.
Do they work with autofill?
Yes. Autofilled inputs no longer show their placeholder, so the label floats as soon as the browser fills them.
Why does the outlined style need a background colour?
The notch is a patch of background behind the label covering the border; on a varied background use the filled or classic style.