DEV Community

Cover image for How to create Google's Material Design Text Input Field using CSS and JavaScript?
Murtuzaali Surti
Murtuzaali Surti

Posted on

How to create Google's Material Design Text Input Field using CSS and JavaScript?

In this tutorial, we are trying to recreate Google's text input field animation and design from scratch with the help of CSS as well as JavaScript.

HTML

We are not going to use pseudo-elements to create this effect, but we will be taking help of div element instead.

We are wrapping the input element and its related divs inside a container. To create a placeholder, we have defined a separate div which will act as a placeholder rather than using the :placeholder pseudo-element.

<div class="input-contain">
  <input type="text" id="fname" name="fname" autocomplete="off" value="" aria-labelledby="placeholder-fname">
  <label class="placeholder-text" for="fname" id="placeholder-fname">
     <div class="text">First Name</div>
  </label>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS

First of all, let's define the properties for the input element and it's container.


.input-contain{
    position: relative;
}
input{
    height: 5rem;
    width: 40rem;
    border: 2px solid black;
    border-radius: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

We will be placing the placeholder text on top of the input element by setting the position of the placeholder text to absolute so that it matches the width and height of the input container.

.placeholder-text{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    border: 3px solid transparent;
    background-color: transparent;
    display: flex;
    align-items: center;
}
Enter fullscreen mode Exit fullscreen mode

But there's an issue. You can't click on the input element because the placeholder element is on the top of the input element. In order to overcome this situation, just set the value of pointer-events to none for the placeholder element.

.placeholder-text{
    pointer-events: none;
}
Enter fullscreen mode Exit fullscreen mode

Now, let's style the placeholder text a little bit.

.text{
    font-size: 1.4rem;
    padding: 0 0.5rem;
    background-color: transparent;
    color: black;
}

input, .placeholder-text{
    font-size: 1.4rem;
    padding: 0 1.2rem;
}
Enter fullscreen mode Exit fullscreen mode

Next up, let's define what should happen when the input element is focused.
We are going to change the border-color rather than keeping the outline on focus event.

input:focus{
    outline: none;
    border-color: blueviolet;
}
Enter fullscreen mode Exit fullscreen mode

We want the placeholder text to translate along Y-axis(to go up) and reduce it's font-size a little bit when the input element is focused. Also, we can change the color of the placeholder text. Here's how we can do that. Change the background-color to resemble the surrounding color to make it more elegant.

input:focus + .placeholder-text .text{
    background-color: white;
    font-size: 1.1rem;
    color: black;
    transform: translate(0, -170%);
    border-color: blueviolet;
    color: blueviolet;
}
Enter fullscreen mode Exit fullscreen mode

For a smooth transition, add transition property to the placeholder text.

.text{
    transform: translate(0);
    transition: transform 0.15s ease-out, font-size 0.15s ease-out, background-color 0.2s ease-out, color 0.15s ease-out;
}
Enter fullscreen mode Exit fullscreen mode

Up until now everything is fine, but now a problem arises. When you enter text in the input element and then remove the focus from the input element, the placeholder text comes to it's original position and we don't want that. We want the placeholder text to remain above the input text when something is already entered in the input field. Hence, we will be taking the help of JavaScript and we will modify CSS.

If you remember, we have already defined value attribute for the input element. This will come handy.

<input type="text" id="fname" name="fname" autocomplete="off" value="" aria-labelledby="placeholder-fname">
Enter fullscreen mode Exit fullscreen mode

Let's modify some CSS. As already discussed, when the value is an empty string, the placeholder text should come back to its original position, but when the value is other than an empty string, the placeholder text should remain transformed(above the input text). We can achieve that by defining a :not pseudo-class on the input element value. Here's how we can do that.

input:focus + .placeholder-text .text, :not(input[value=""]) + .placeholder-text .text{
    background-color: white;
    font-size: 1.1rem;
    color: black;
    transform: translate(0, -170%);
}

input:focus + .placeholder-text .text{
    border-color: blueviolet;
    color: blueviolet;
}
Enter fullscreen mode Exit fullscreen mode

But wait. The value attribute will remain the same in HTML. How can we change and set it to the string entered by the user? That's where JavaScript comes into action.

We will set the value of the value attribute to the string entered by the user just like this,

let input_element = document.querySelector("input");

input_element.addEventListener("keyup", () => {
    input_element.setAttribute("value", input_element.value);
})
Enter fullscreen mode Exit fullscreen mode

That's it. You just made a modern material design text input field.

Here's the final output:

Top comments (10)

Collapse
 
keeran_raaj profile image
Raj Kiran Chaudhary

This works pretty good for single input field. But when there are two inputs, then there is a slight problem. On clicking somewhere, the label of second input field comes down. Can you please help??

Collapse
 
keeran_raaj profile image
Raj Kiran Chaudhary

Thank you @murtuzaalisurti . I solved the problem by using 'querySelectorAll'

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

⚡🙌

Collapse
 
ishayu profile image
Ishayu Roy

"When you enter text in the input element and then remove the focus from the input element, the placeholder text comes to it's original position": this problem is not fixed for me, please help

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Make a codepen and send it here

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Have you followed each and every step?

Collapse
 
tbroyer profile image
Thomas Broyer

Please make .placeholder-text or .text a <label> (and properly associate it with the input of course; also put it before the input if possible). There's no reason to compromise on accessibility.

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Now it's improved! Thanks for letting me know!

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
mrsandman101 profile image
A.B.Santhosh

Landing page looks like a couple of css files are not loaded. Make your landing page more user friendly