DEV Community

loading...

Criando um input com label flutuante no ReactJS

rafacdomin profile image Rafael Domingues ・3 min read

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:

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.

$ 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:

<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:

#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:

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:

#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:

#float-label label {
  ...

  position: absolute;
  transform: translate(0, 26px) scale(1);
}

Temos o seguinte resultado:

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:

#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:

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:

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:

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:

#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

Discussion

pic
Editor guide