LoginApp: Refining the Login Form with Floating Labels
Published: October 9, 2025
In this post, I’ll walk through how I refined the username and password fields in LoginApp with floating labels and improved focus states. I wanted the labels to sit inside the input fields when empty, then float above when the user types or focuses. Tailwind makes this possible using a combination of utilities.
I wrapped each input and label inside a relative container. The
label itself is positioned absolutely and animated using
transition-all. To detect when the input is empty, I
added placeholder=" " on each field. This works
together with peer on the input, which lets the label
react to the input’s state using selectors like
peer-placeholder-shown and peer-focus.
Here’s the structure I used for the username field:
<div className="relative mb-4">
<input
type="text"
placeholder=" "
className="peer w-full border rounded-md p-2 pt-4 focus:outline-none focus:ring-2 focus:ring-indigo-400"
/>
<label className="absolute left-3 -top-2 bg-white px-1 text-gray-500 transition-all peer-placeholder-shown:top-4 peer-placeholder-shown:text-gray-400 peer-focus:-top-2 peer-focus:text-blue-500 peer-focus:text-sm">
Username
</label>
</div>
Here’s what each part does:
-
placeholder=" "— lets Tailwind detect when the input is empty. -
peer— allows the label to react to the input’s state. -
absolute+transition-all— positions the label and animates it smoothly. -
peer-placeholder-shown:top-4— moves the label inside the input when it’s empty. -
peer-focus:-top-2+peer-focus:text-blue-500+peer-focus:text-sm— floats the label up with a smaller blue font when the input is focused.
Initially, the label would revert to gray after typing, which felt inconsistent. To fix this, I set the label’s default state to look “active” once the field contains text. I also made the typed text darker for better contrast:
<input
type="text"
placeholder=" "
className="peer w-full border rounded-md p-2 pt-4 text-gray-800 focus:outline-none focus:ring-2 focus:ring-indigo-400"
/>
<label className="absolute left-3 -top-2 bg-white px-1 text-blue-500 text-sm transition-all peer-placeholder-shown:top-4 peer-placeholder-shown:text-gray-400 peer-placeholder-shown:text-base peer-focus:-top-2 peer-focus:text-blue-500 peer-focus:text-sm">
Username
</label>
For the password field, I repeated the same pattern. The result is an interactive form where each label smoothly floats above the input on focus or when text is entered, while the placeholder remains subtle.
Implementing these floating labels with Tailwind taught me how
powerful utility-first styling can be. By combining
peer, placeholder-shown, and
focus states, I can create complex, interactive forms
without writing custom CSS.