- What is a float label?
These days I was working in a project that the inputs had a different behavior, while empty they had a normal placeholder but when filled, the placeholder moved above the typed text, something that looks very simple but that would make a difference in the page layout.
Example:
After some research I decided to share my learning and help you put that finishing touch on your projects.
- How to do?
Creating a new project
First of all I will create a new project in React with yarn:
$ yarn create react-app float-input
After cleaning up the code that the command did for us, I created a div that contains an input and a label like this:
<div id="float-label">
<input type="email" />
<label htmlFor="email">
E-mail
</label>
</div>
Now let's stylize with css
, feel free to style it the way you prefer, in my case I did the following:
#float-label {
display: flex;
flex-direction: column;
min-width: 350px;
}
#float-label input {
width: 100%;
height: 56px;
padding: 14px 16px 0 10px;
outline: 0;
border: 1px solid #ddd;
border-radius: 4px;
background: #fff;
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
}
#float-label label {
font-size: 16px;
font-family: Arial, Helvetica, sans-serif;
padding: 0 12px;
color: #999;
pointer-events: none;
}
Our input now looks like this:
Doing animation with CSS
Now we start with the "magic", which consists of a transition and the behavior of position absolute, which has the axes referring to the parent element, if it is position relative.
First we add position relative to the css
of our div
:
#float-label {
...
position: relative;
}
Now we add position absolute to our label
and a transform to center our label
, as if it were a placeholder for our input
:
#float-label label {
...
position: absolute;
transform: translate(0, 26px) scale(1);
}
We have the following result:
Now we are going to do the animation with a transition and use the focus-within
to apply the translate effect to change the position and scale in ourlabel
:
#float-label label {
...
transform-origin: top left;
transition: all 0.2s ease-out;
}
#float-label:focus-within label {
transform: translate(0, 12px) scale(0.75);
}
We now have the following result but still with a small problem that we are going to fix:
Doings changes in ReactJS
First we add a className to our label
, which will depend directly on a variable that we will create in the state of our React component through the useState
hook:
const [isActive, setIsActive] = useState(false);
return(
...
<label className={ isActive ? "Active" : ""} htmlFor="email" >
E-mail
</label>
...
);
To change our state variable we will create a function that handles what was typed in our input:
const [value, setValue] = useState('');
function handleTextChange(text) {
setValue(text);
if (text !== '') {
setIsActive(true);
} else {
setIsActive(false);
}
}
return(
...
<input
type="email"
value={value}
onChange={(e) => handleTextChange(e.target.value)}
/>
);
The function is called whenever we type something in the input
and is responsible for changing our value and checking if the text in the input is actually a word.
Finally, we stylized our Active class in our css
with the same code used before to make our label
change position:
#float-label .Active {
transform: translate(0, 12px) scale(0.75);
}
And our animation is ready! Tell me below if you liked and if you managed to do it :)
Remembering that if you know a better way to do this same functionality, feel free to share too!
Based on: https://velhobit.com.br/design/como-fazer-efeito-float-label-animado-com-css3-puro.html
Top comments (10)
Really useful, thank you! I've replicated everything from above and have run in to a bit of trouble when I have multiple inputs fields.
Typing in to one field sets the isActive state to true, as a result adding the label styling to all inputs, not just the single input I have populated. Any suggestions on how to work around this?
Thanks
Insted of using a className, I add the "required" Attribute on input, and in the css use "valid" insted "focus-within".
The result is similar, i don´t use the transform
Here is a part of my code:
CSS
index.js
Separate this input into a component and use that component instead so that each input will have a different isActive state, or manually create a different property isActive for each input you will use
Thank you. I was actually trying to make the transform effect manipulating the input effect directly from JS.
This worked perfectly for me, thank you!!!!
one small issue with this. transform translate is based on the label width so the label will be offset differently based on the label text length
Thank you, great example and helped me to understand how to do floating label in React
You're a great help!! Cheers
Thank You!
Thanks for the example. Great stuff!
I loved the result!!!