Criando um input com label flutuante no ReactJS
Tags: web, react, tutorial, frontend
Published: 2020-08-12 01:18:59

# O que é um label flutuante?

Esses dias eu estava trabalhando em um projeto e me deparei com o design dos inputs, que tinham um placeholder enquanto vazios e quando preenchidos o placeholder ficava acima do texto digitado, algo bem simples mas que faria uma diferença no layout da página.

Exemplo: 

<img src="https://dev-to-uploads.s3.amazonaws.com/i/3f3xmx9tb3310r7wsl1c.gif" width=600 />

Depois de pesquisar um pouco decidi fazer um pequeno post e compartilhar para quem sabe ajudar a dar um toque a mais no design dos seus Inputs. Vamos lá!

# Como fazer?

Primeiramente vou criar um novo projeto do React com yarn.

```bash 
$ yarn create react-app float-input
```

Depois de limpar o código que o react criou sozinho vou criar uma `div` contendo um elemento `input` e um elemento `label`, da seguinte forma:

```jsx
<div id="float-label">
  <input type="email" />

  <label htmlFor="email">
    E-mail
  </label>
</div>
```

E agora vou estilizar um pouco com `css`, fique a vontade para estilizar da forma que preferir, no meu caso fiz o seguinte:

```css
#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;
}
```

Por fim nosso `label` e nosso `input` estão aparecendo assim na página: 

<img src="https://dev-to-uploads.s3.amazonaws.com/i/b2ybaoyspaq2wnxjrjed.png" width=400/>

Agora começamos com a "mágica", que consiste em uma _transition_ e o comportamento do _absolute_, que tem os eixos referentes ao elemento pai, caso esse seja _relative_.

Primeiro adicionamos _position relative_ ao `css` da nossa `div` pai:
```css
#float-label {
  ...

  position: relative;
}
```

Agora adicionamos _position absolute_ ao nosso `label` e um _transform_ para centralizar nosso `label`, como se ele fosse um placeholder para nosso `input`:
```css
#float-label label {
  ...
  
  position: absolute;
  transform: translate(0, 26px) scale(1);
}
```

Temos o seguinte resultado:
<img src="https://dev-to-uploads.s3.amazonaws.com/i/1c81x1ze8ioj92mw5nov.png" width=400/>

Agora vamos fazer a animação com um _transition_ e uso do `focus-within` para aplicar o efeito de translate para mudar a posição e scale na nossa `label`:

```css
#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);
}
```

Temos agora o seguinte resultado mas ainda com um pequeno problema que já vamos corrigir:

<img src="https://dev-to-uploads.s3.amazonaws.com/i/c73bl7gaeygkwckllkri.gif" width=600/>

Para corrigir esse problema eu encontrei a seguinte solução:

Primeiro adicionamos um className ao nosso `label`, que vai depender diretamente de uma variável que vamos criar no estado do nosso componente React através do hook `useState`:

```jsx
const [isActive, setIsActive] = useState(false);

return(
...
  <label className={ isActive ? "Active" : ""} htmlFor="email" >
  E-mail
  </label>
...
);
```

Para alterar essa nossa variável do estado criaremos uma função que lida com o que foi digitado no nosso `input`:

```jsx
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)}
/>
);
```

A função é chamada sempre que digitamos algo no `input` e é responsável por mudar nosso value e verificar se o texto no input é de fato alguma palavra.

Por fim, estilizamos nossa classe Active no nosso `css` com o mesmo código utilizado antes para fazer nosso `label` mudar de posição, ficando assim:

```css
#float-label .Active {
  transform: translate(0, 12px) scale(0.75);
}
```

E nossa animação está pronta! Me diz ai embaixo o que você achou e se conseguiu fazer ai :)

Lembrando que se conhecer uma forma melhor de fazer esta mesma funcionalidade, fique a vontade para compartilhar também!

Baseado em: https://velhobit.com.br/design/como-fazer-efeito-float-label-animado-com-css3-puro.html