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.