Jacob Ruiz

View Original

How to transition placeholder text into a label in React (Floating label inputs)

Floating label inputs are input fields whose placeholder text animates into a label when you start typing. You might recognize this pattern from Google’s Material Design.

In this post I’ll explain how you can build your own floating label input using React and a little CSS.

If you just want the code, scroll to the end. You’ll find a Codesanbox where you can see the full code, try out the result, and customize it to your liking.

Step 1: Put the label and input inside a container div

Normally a label sits on top of an input field. But for our use case, we want the label to be in two positions depending on the interaction state:

  1. Empty state: Sitting in the middle of the input field, acting as placeholder text

  2. Filled/typing state: Pinned to the top left corner of the input field, acting as a label.

The HTML looks something like this:

See this content in the original post

Step 2: Set the container div position to relative so we can have more control over the position of the label

In your CSS file, set the position of the container div to “relative”. Also, set display to “flex” and flex-direction to “column”.

See this content in the original post

Step 3: Position the label in it’s “placeholder” state

Now that the we’ve set the parent div to use relative positioning, we can use absolute positioning on our label to put it in the middle of the field so it looks like placeholder text. We can also add a few other styles to make it look good.

See this content in the original post

Note the line: transform-origin: top left. This is important. Without this, if we were to scale down the label into it’s “label state”, the transform origin would be in the middle, which would make it impossible for us to pin a label of any length exactly to the top left corner. By setting the transform-origin to top left, we can get it right every time.

Step 3: Use :focus-within to set the position of the label when the input is focused

CSS has a handy pseudo-selector called ":focus-within”. This lets us target a parent div whose child is currently in focus. We need this so we can say the following: “Hey parent div, when there is focus within you (the input field is in focus), then style the label like this”:

See this content in the original post

This is the “label” state of the label element, where we scale it down and pin it to the top left corner of the field.

Step 4: Use React state to handle the case where the field is filled but not in focus

We’re almost there, but we’re running into the limitations of CSS. We need a way to change the styling based on whether or not the input has text inside of it.

  • If there is text, put label into label state, even if the field is not in focus

  • If there is no text, put label into placeholder text

To do this, we just need to do the following in React:

  • Use useState to store the value of the input field

  • onChange, update the value

  • Conditionally add a class of “filled” to the label as long as value is not an empty string

Our React component now looks like this:

See this content in the original post

Try out the demo in Codesandbox

Feel free to fork the code as customize it to your liking.

See this content in the original post