W3docs

CSS :invalid Pseudo-Classe

Aprenda como o CSS :invalid estiliza campos de formulário com falha de validação, com exemplos, dicas de acessibilidade e suporte a navegadores.

A pseudo-classe CSS :invalid corresponde a controles associados a formulários — como <input>, <select> e <textarea> — cujo valor atual falha nas restrições de validação nativas do navegador. É a metade visual da API de validação de restrições do HTML: o navegador avalia a validade e :invalid permite estilizar o resultado com CSS puro, sem JavaScript.

Esta página cobre exatamente quando :invalid corresponde, como estilizá-lo sem assustar os usuários antes que tenham digitado qualquer coisa, a particularidade do botão de rádio, a alternativa moderna :user-invalid e como manter o feedback de erro acessível.

Quando um elemento corresponde a :invalid?

Um controle corresponde a :invalid sempre que possui pelo menos uma restrição de validação e seu valor atual viola essa restrição. Gatilhos comuns:

RestriçãoAtributo / tipoFalha quando…
Obrigatório mas vaziorequiredo campo não tem valor
Formato de e-mail incorretotype="email"o valor não é um e-mail sintaticamente válido
Formato de URL incorretotype="url"o valor não é uma URL absoluta válida
Fora do intervalomin / max em type="number", type="date", etc.o valor está fora do intervalo permitido
Passo incorretostepo valor não se alinha com o intervalo de passo
Incompatibilidade de padrãopatterno valor não corresponde à expressão regular
Comprimento inválidominlength / maxlengtho comprimento do valor está fora do intervalo permitido

Se um controle não tiver nenhuma restrição (um <input type="text"> simples sem atributos extras), ele é considerado sem restrições e nem :valid nem :invalid se aplica a ele.

Um elemento <fieldset> corresponde a :invalid quando qualquer um dos controles de formulário descendentes for inválido.

Para o lado oposto, veja a pseudo-classe :valid, que corresponde a controles que passam em todas as restrições. A pseudo-classe :required corresponde a campos obrigatórios independentemente de terem um valor.

Sintaxe

:invalid {
  /* declarations applied to all invalid form controls */
}

Delimite :invalid a um tipo de elemento específico para manter os estilos previsíveis:

input:invalid,
textarea:invalid {
  border: 2px solid #c00;
  outline: none;
}

Exemplo básico

O campo de e-mail abaixo está pré-preenchido com um endereço malformado ("not-an-email"), portanto corresponde a input:invalid ao carregar e recebe uma borda vermelha.

<!DOCTYPE html>
<html>
  <head>
    <title>:invalid example</title>
    <style>
      input:invalid {
        border: 2px solid #c00;
        background-color: #fff0f0;
      }
      input:valid {
        border: 2px solid #090;
        background-color: #f0fff0;
      }
    </style>
  </head>
  <body>
    <h2>:invalid selector example</h2>
    <form>
      <label for="email">Email:</label>
      <input id="email" type="email" value="not-an-email" required />
    </form>
  </body>
</html>

Evitando o "vermelho prematuro"

A armadilha mais comum de :invalid: um campo required vazio já é inválido no momento em que a página carrega, então um formulário recém-aberto pode ficar todo vermelho antes que o usuário tenha digitado qualquer coisa. Isso parece acusatório.

Opção 1 — estilizar apenas enquanto o campo está focado

Mostre a borda de erro somente enquanto o usuário está ativamente no campo:

input:invalid:focus {
  border-color: #c00;
  outline: 2px solid #c00;
  outline-offset: 1px;
}

É simples, mas desaparece no momento em que o usuário pressiona Tab para sair, fazendo com que um campo obrigatório em branco pareça correto novamente.

Opção 2 — ocultar o erro enquanto o placeholder estiver visível

:placeholder-shown é verdadeiro quando o texto do placeholder é exibido (ou seja, o campo está vazio). Combiná-lo com :not faz o estilo de :invalid entrar em ação somente depois que o usuário tiver digitado algo:

/* Only show the error style when the field has a value that is invalid */
input:invalid:not(:placeholder-shown) {
  border-color: #c00;
}

Isso é eficaz, mas exige que todo campo tenha um atributo placeholder definido — caso contrário, :placeholder-shown nunca é verdadeiro e a proteção não funciona.

Opção 3 — usar :user-invalid (padrão moderno)

A pseudo-classe :user-invalid foi criada especificamente para resolver esse problema. Ela se comporta como :invalid, mas só corresponde depois que o usuário interagiu com o controle (digitou nele, saiu dele ou enviou o formulário):

/* Supported in all modern browsers as of 2024 */
input:user-invalid {
  border-color: #c00;
}

/* Fallback for older browsers */
@supports not selector(:user-invalid) {
  input:invalid:not(:placeholder-shown) {
    border-color: #c00;
  }
}

:user-invalid é a solução mais limpa quando você pode contar com ela. O Firefox tem suportado isso como :-moz-ui-invalid há anos; o padrão :user-invalid agora está em todos os navegadores modernos.

Abordagem de estilização

Uma borda completa de 2 px em vermelho intenso é legível, mas impactante. Considere combinar uma mudança de borda com um box-shadow sutil para um visual mais suave:

input:invalid:not(:placeholder-shown) {
  border-color: #c00;
  box-shadow: 0 0 0 3px rgba(204, 0, 0, 0.15);
}

Evite depender apenas da cor — veja a seção Acessibilidade abaixo.

Armadilhas

Botões de rádio

Quando um grupo de botões de rádio tem required em um de seus inputs, todos os botões do grupo correspondem a :invalid enquanto nenhum está selecionado. Estilizar círculos de rádio minúsculos não é prático; em vez disso, estilize o <fieldset> ou <label> ao redor:

/* Style the fieldset, not the radio buttons themselves */
fieldset:invalid {
  border: 2px solid #c00;
  border-radius: 4px;
  padding: 8px 12px;
}

Todos os botões de rádio em um grupo compartilham o mesmo atributo name — é isso que os torna um grupo no modelo de validade do navegador.

Campos opcionais vazios

Um <input type="text"> simples sem required, sem pattern e sem restrições de comprimento é sempre :valid mesmo quando vazio. :invalid só é acionado quando uma restrição existe e é violada.

select e textarea

<select> corresponde a :invalid se for required e seu value atual for uma string vazia (um padrão comum é um <option value=""> de placeholder "-- escolha --" no topo). <textarea> segue as mesmas regras que <input> para required, minlength e maxlength.

Firefox e :-moz-ui-invalid

O Firefox aplica estilos há muito tempo via :-moz-ui-invalid, que só é ativado após a interação do usuário — efetivamente o comportamento de :user-invalid embutido. Se você adicionar suas próprias regras :invalid e testar no Firefox, o campo pode parecer correto (porque o guard de interação do usuário padrão do navegador está ativo), depois se comportar de forma diferente no Chrome (onde o guard padrão está desativado). Defina regras explícitas e use :user-invalid com um fallback para obter comportamento consistente.

Acessibilidade

A cor sozinha nunca é suficiente para comunicar um erro — usuários com deficiências na visão de cores podem não perceber uma borda vermelha. Combine o estilo de :invalid com:

  • Uma mensagem de texto visível explicando o que deu errado e como corrigir.
  • Um ícone ou símbolo junto à mudança de cor (por exemplo, um ✕ ou ícone de aviso).
  • aria-invalid="true" no controle para que leitores de tela o anunciem como inválido.
  • aria-describedby apontando para o elemento de mensagem de erro para que a descrição seja lida automaticamente.
<label for="email">Email address</label>
<input
  id="email"
  type="email"
  aria-invalid="true"
  aria-describedby="email-error"
  required
/>
<span id="email-error" role="alert">
  Please enter a valid email address.
</span>

O role="alert" no span de erro faz com que os leitores de tela anunciem a mensagem assim que ela aparecer no DOM, mesmo sem foco.

Pseudo-classes relacionadas

Pseudo-classeCorresponde quando…
:valido controle passa em todas as suas restrições
:requiredo controle tem o atributo required
:optionalo controle não tem required
:out-of-rangeo valor de um input numérico/data excede min/max
:in-rangeo valor de um input numérico/data está dentro de min/max
:placeholdero texto de placeholder de um input
:focuso controle atualmente tem foco do teclado

Suporte a navegadores

:invalid faz parte do Selectors Level 4 e tem suporte em todos os principais navegadores há muitos anos. :user-invalid (a variante com consciência de interação) foi lançada no Chrome 119, Firefox 88 (como :-moz-ui-invalid muito antes) e Safari 16.5.

Para mais informações sobre os atributos de restrição nativos do HTML, veja <input> e HTML Forms.

Prática

Prática
Qual é a função da pseudo-classe ':invalid' no CSS?
Qual é a função da pseudo-classe ':invalid' no CSS?
Was this page helpful?