Floating Form Field with Tailwind CSS

Learn how to build a floating form field with Tailwind CSS

Authors
Marc Stammerjohann Marc Stammerjohann
Published at

In the following lesson you will learn how to use Tailwind CSS utility-first approach to create a floating form field known from Material Design. This is inspired by the awesome video from fireship.io.

Floating Form

You can follow along in a new project or get the source code from GitHub.

Setup

Let's start in an empty directory and setup up a default package.json file using npm init -y.

Setup Tailwind CSS

Setup Tailwind by installing

npm i -D tailwindcss postcss-cli autoprefixer

Generate a Tailwind config file as you will customize Tailwind for the floating form field later.

npx tailwindcss init

Create postcss.config.js file requiring tailwindcss and autoprefixer as a plugin:

module.exports = {
  plugins: [
    require("tailwindcss"),
    require("autoprefixer")
  ]
};

Create your tailwind styles under css/tailwind.css

@tailwind base;
@tailwind components;
@tailwind utilities;

Add those scripts to your package.json one to build and the other to watch changes made to the tailwind.css file.

"scripts": {
  "build": "postcss css/tailwind.css -o public/build/tailwind.css",
  "dev": "postcss css/tailwind.css -o public/build/tailwind.css -w"
},

Setup HTML

Start with the following simple HTML layout - create an index.html in the public directory.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>FFFwT</title>

    <link rel="stylesheet" href="build/tailwind.css" />
  </head>
  <body class="antialiased p-10">
    <form>
      <div>
        <input type="text" name="username" placeholder=" " />
        <label for="username">Username</label>
      </div>
    </form>
  </body>
</html>

You can use live-server to start a dev-server with live reload.

live-server public

Here you have your starting point - an input and a label.

Input and Label

Let's add styles to create a floating form field.

Floating Form Field

Focus Border

Start by adding a bottom border to the div using border-b-{width}

<div class="border-b-2">
  <input type="text" name="username" placeholder=" " />
  <label for="username">Username</label>
</div>

Border bottom

To change the border color when the input is focused use the pseudo-class focus-within. Enable the focus-within variant in Tailwind for borderColor by adding it in the tailwind.config.js under the variants section:

variants: {
  borderColor: ['responsive', 'hover', 'focus', 'focus-within'],
},

Now add focus-within:border-blue-500 to change the border color on focus

<div class="my-4 border-b-2 focus-within:border-blue-500">
  <input type="text" name="username" placeholder=" " />
  <label for="username">Username</label>
</div>

Change border color on focus

Floating Label

Begin with changing the position of the div to relative so that you can use top to control the position of the label. Add class="absolute top-0" to the label.

input is an inline element, add the Tailwind block class to change it to a block element. Also set the input width to 100% with w-full to tap the input on the whole form field. Additionally, add appearance-none and focus:outline-none to the input to remove browser specific styles.

<div class="relative my-4 border-b-2 focus-within:border-blue-500">
  <input type="text" name="username" placeholder=" " class="block w-full appearance-none focus:outline-none" />
  <label for="username" class="absolute top-0">Username</label>
</div>

Currently the label is covering the input field and preventing you from focusing the input ๐Ÿ™ˆ.

Label is covering up the input

Let's change the z-index of the label to be behind the input field by setting it to z-index: -1. Extend the Tailwind theme to generate a negative z-index for you:

theme: {
  extend: {
    zIndex: {
      "-1": "-1",
    },
  },
}

Add -z-1 class to the label, now the label is not visible anymore. Add bg-transparent to the input.

<div class="relative my-4 border-b-2 focus-within:border-blue-500">
  <input type="text" name="username" placeholder=" " class="block w-full appearance-none focus:outline-none bg-transparent" />
  <label for="username" class="absolute top-0 -z-1">Username</label>
</div>

The label is visible again and the input field can be focused by taping on the label too ๐Ÿต.

Next make the label float above the input, again, using the pseudo-class focus-within. Open your tailwind.css and add the following CSS selector:

input:focus-within ~ label {
 
}

Now use Tailwind's @apply to transform, scale and change the label text color on input focus.

input:focus-within ~ label {
 @apply transform scale-75 -translate-y-6 text-blue-500;
}

Also add duration-300 to your label class to control the labels transition duration.

Floating label on focus

Awesome the label is floating ๐ŸŽˆ, however, it stops floating when you remove the focus from the input ๐Ÿ˜ž. The label should float if the input field has some content. Target the placeholder, if its not shown input:not(:placeholder-shown) ~ label thus the input has content and the label should float.

input:focus-within ~ label,
input:not(:placeholder-shown) ~ label {
  @apply transform scale-75 -translate-y-6;
}

input:focus-within ~ label {
  @apply text-blue-500;
}

Floating label without focus

Yeah ๐Ÿคฉ, the label floats on focus and if the input has content. It seems the label is not aligned with the input field. Set transform-origin on the label to 0%. Let Tailwind generate it for you, open tailwind.config.js and add it to the theme section:

theme: {
  extend: {
    transformOrigin: {
      "0": "0%",
    },
    zIndex: {
      "-1": "-1",
    },
  },
}

Now add origin-0 to the label and finally you have your own floating form field made with Tailwind CSS ๐Ÿ˜๐Ÿš€

Floating Form Field

Building a form

Let's build a form field by duplicating the floating form field or by extracting the styles with @apply.

Add space-y-{size} to the form to add margin between your input fields. You could also wrap it with a card.

 <form class="max-w-sm mx-auto rounded-lg shadow-xl overflow-hidden p-6 space-y-10">
  <h2 class="text-2xl font-bold text-center">Login</h2>
  <div class="relative border-b-2 focus-within:border-blue-500">
    <input type="text" name="username" placeholder=" " class="block w-full appearance-none focus:outline-none bg-transparent" />
    <label for="username" class="absolute top-0 -z-1 duration-300 origin-0">Username</label>
  </div>
  <div class="relative border-b-2 focus-within:border-blue-500">
    <input type="text" name="email" placeholder=" " class="block w-full appearance-none focus:outline-none bg-transparent" />
    <label for="email" class="absolute top-0 -z-1 duration-300 origin-0">Email</label>
  </div>
  <div class="relative border-b-2 focus-within:border-blue-500">
    <input type="password" name="password" placeholder=" " class="block w-full appearance-none focus:outline-none bg-transparent" />
    <label for="password" class="absolute top-0 -z-1 duration-300 origin-0">Password</label>
  </div>
</form>

Here you have your first form using the floating form field

Floating form

Next, try out another style - Outline Form Field.

Outline Form Field

In this style the form field has an outline all around and the label floats into the outline. Reuse the floating form field and change border-b-2 to border-2 this gives you the outline.

Add padding p-4 to create space inside the outline and increase the font size text-lg of the input and the label.

<div class="relative border-2 focus-within:border-blue-500">
  <input type="text" name="username" placeholder=" " class="block p-4 w-full text-lg appearance-none focus:outline-none bg-transparent" />
  <label for="username" class="absolute top-0 p-4 text-lg -z-1 duration-300 origin-0">Username</label>
</div>

Look at our outline form field

Outline form field

Focus the input and you notice the label is not covering up the outline.

Floating label not covering the outline

To make the label cover up the outline customize the floating CSS applied to the outline form field. Duplicate the custom CSS in your tailwind.css and add .outline class to both selectors. Add outline class to the div around your input and label.

.outline input:focus-within ~ label,
.outline input:not(:placeholder-shown) ~ label {
  @apply transform scale-75 -translate-y-6;
}

Update a few styles on the label to remove the top and bottom padding - py-0. Also reduce the left and right padding to px-1, add margin left ml-3 to align it with the input. Reset the z-index to z-0 that the label is above the outline. Finally, reduce the translate y value until the label is perfectly matching the outline.

.outline input:focus-within ~ label,
.outline input:not(:placeholder-shown) ~ label {
  @apply transform scale-75 -translate-y-4 z-0 ml-3 px-1 py-0;
}

Perfect the label is exactly on the outline, but the line is still visible.

Floating label covers outline with line through

To hide the outline set the background of the label to the same background of the container where you place the form field. Add bg-white to the label, this should do the trick.

<div class="outline relative border-2 focus-within:border-blue-500">
  <input type="text" name="username" placeholder=" " class="block p-4 w-full text-lg appearance-none focus:outline-none bg-transparent" />
  <label for="username" class="absolute top-0 text-lg bg-white p-4 -z-1 duration-300 origin-0">Username</label>
</div>

Now you have the outline form field working too. ๐Ÿ‘

Building a form

Now create a form using the outline style.

<form class="max-w-sm mx-auto rounded-lg shadow-xl overflow-hidden p-6 space-y-10">
  <h2 class="text-2xl font-bold text-center">Login</h2>
  <div class="outline relative border-2 focus-within:border-blue-500">
    <input type="text" name="username" placeholder=" " class="block p-4 w-full text-lg appearance-none focus:outline-none bg-transparent" />
    <label for="username" class="absolute top-0 text-lg bg-white p-4 -z-1 duration-300 origin-0">Username</label>
  </div>
  <div class="outline relative border-2 focus-within:border-blue-500">
    <input type="email" name="email" placeholder=" " class="block p-4 w-full text-lg appearance-none focus:outline-none bg-transparent" />
    <label for="email" class="absolute top-0 text-lg bg-white p-4 -z-1 duration-300 origin-0">Email</label>
  </div>
  <div class="outline relative border-2 focus-within:border-blue-500">
    <input type="password" name="password" placeholder=" " class="block p-4 w-full text-lg appearance-none focus:outline-none bg-transparent" />
    <label for="password" class="absolute top-0 text-lg bg-white p-4 -z-1 duration-300 origin-0">Password</label>
  </div>
</form>

Outline Form

If you followed along, create and customize your own floating form field w/ Tailwind CSS. Send me your own design on Twitter @mrcjln.

Sponsor us

Did you find this post useful? We at notiz.dev write about our experiences developing Apps, Websites and APIs and develop Open Source tools. Your support would mean a lot to us ๐Ÿ™. Receive a reward by sponsoring us on Patreon or start with a one-time donation on GitHub Sponsors.

Table of Contents

Top of Page Comments Related Articles

Related Posts

Find more posts like this one.

Authors
Marc Stammerjohann
July 08, 2022

Maizzle: Craft beautiful HTML emails with Tailwind CSS

Send beautiful HTML emails via NestJS crafted with Maizzle and Tailwind CSS
Maizzle Tailwind CSS NestJS Read More
Authors
Marc Stammerjohann
December 15, 2020

Tailwind CSS Purge: Optimize Angular for Production

Remove unused Tailwind CSS utilities from your Angular production build for best performance
Tailwind CSS Angular Scully Read More
Authors
Marc Stammerjohann
October 29, 2020

Jamstack: Angular + Scully + Tailwind CSS

Use Angular's static site generator Scully and style it with Tailwind CSS
Scully Angular Tailwind CSS Read More
Authors
Marc Stammerjohann
June 03, 2021

Angular with Tailwind CSS

Learn how to style Angular applications with Tailwind CSS
Angular Tailwind CSS CSS Read More

more coming soon

Get in Touch!

Sign up for our newsletter

Sign up for our newsletter to stay up to date. Sent every other week.

We care about the protection of your data. Read our Privacy Policy.