CSS :indeterminate Pseudo Classe
A pseudo-classe CSS :indeterminate seleciona elementos em estado indeterminado. Leia sobre ela e pratique com exemplos.
A pseudo-classe CSS :indeterminate corresponde a controles de formulário que estão em um estado indeterminado — um terceiro estado que não é nem "ligado" nem "desligado". Este capítulo explica quais elementos podem entrar nesse estado, como acioná-lo e como estilizá-lo, com exemplos executáveis para checkboxes, grupos de radio e barras de progresso.
O que significa "indeterminado"
Alguns controles de formulário normalmente têm dois estados (marcado / desmarcado, ou um valor de progresso conhecido). O estado indeterminado representa uma terceira condição "indefinida". A pseudo-classe :indeterminate tem como alvo três tipos de elementos:
- Checkboxes (
<input type="checkbox">) cuja propriedade DOMindeterminateestá definida comotrue. Este é o clássico checkbox tri-estado "alguns, mas não todos os itens filhos estão selecionados". - Botões de radio (
<input type="radio">) — todos os botões de um grupo com o mesmo nome são correspondidos enquanto nenhuma opção desse grupo estiver selecionada. - Barras de progresso (
<progress>) que não possuem atributovalue, o que significa que a duração da tarefa é desconhecida e a barra anima sem um preenchimento fixo.
O estado indeterminado é definido via JavaScript, não CSS — não é possível entrar nele apenas com uma regra CSS. Para checkboxes, você define element.indeterminate = true via JavaScript. Definir essa propriedade não altera checked; as duas são independentes. A aparência visual indeterminada (geralmente um traço em vez de um tique) e uma correspondência com :checked são coisas separadas. Redefinir o formulário com form.reset() limpa o sinalizador indeterminate de um checkbox de volta para false.
A pseudo-classe :checked estiliza o estado marcado, enquanto :indeterminate estiliza o estado indefinido. Um controle pode ser um, o outro, ou nenhum, mas nunca ambos ao mesmo tempo. Você pode combinar :indeterminate com outras pseudo-classes, como :hover para estilizar um elemento indeterminado apenas enquanto o ponteiro estiver sobre ele, ou com :focus para destacá-lo quando receber foco via teclado.
Sintaxe
:indeterminate {
/* css declarations */
}Restrinja o seletor a um tipo de elemento específico para evitar correspondências indesejadas:
/* Only checkboxes */
input[type="checkbox"]:indeterminate { outline: 2px dashed orange; }
/* Only radio buttons */
input[type="radio"]:indeterminate { opacity: 0.7; }
/* Only progress bars */
progress:indeterminate { opacity: 0.5; }Você também pode inverter a correspondência com :not para atingir controles que saíram do estado indeterminado:
/* Style a progress bar once it has a known value */
progress:not(:indeterminate) { border: 2px solid green; }Exemplo: estilizando um checkbox indeterminado
Um checkbox só se torna indeterminado quando JavaScript define a propriedade indeterminate como true. A regra CSS é ativada no momento em que essa propriedade é definida, e é removida assim que ela volta a false. Este exemplo destaca o controle com um box-shadow colorido.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
input:indeterminate {
box-shadow: 0 0 2px 2px #666;
}
</style>
</head>
<body>
<h2>Indeterminate selector example</h2>
<form>
<input type="checkbox" id="box" /> Checkbox
<script>
var checkbox = document.getElementById("box");
checkbox.indeterminate = true;
</script>
</form>
</body>
</html>Caso de uso comum: um checkbox tri-estado "selecionar tudo"
A aplicação mais prática de :indeterminate é um checkbox mestre que resume uma lista de opções: marcado quando todos os filhos estão selecionados, desmarcado quando nenhum está, e indeterminado quando alguns estão. Esse padrão é comum em gerenciadores de arquivos, clientes de e-mail e tabelas de dados.
A lógica JavaScript mantém as propriedades indeterminate e checked do checkbox mestre em sincronia com os checkboxes filhos. O CSS cuida do resto.
<!DOCTYPE html>
<html>
<head>
<title>Tri-state checkbox</title>
<style>
/* Highlight master while in partial-selection state */
#all:indeterminate {
outline: 2px solid #8ebf42;
}
</style>
</head>
<body>
<label><input type="checkbox" id="all" /> Select all</label>
<ul>
<li><label><input type="checkbox" class="child" /> Apples</label></li>
<li><label><input type="checkbox" class="child" /> Bananas</label></li>
<li><label><input type="checkbox" class="child" /> Cherries</label></li>
</ul>
<script>
var all = document.getElementById("all");
var children = document.querySelectorAll(".child");
function syncParent() {
var checked = [...children].filter(function (c) { return c.checked; }).length;
all.checked = checked === children.length;
all.indeterminate = checked > 0 && checked < children.length;
}
all.addEventListener("change", function () {
children.forEach(function (c) { c.checked = all.checked; });
});
children.forEach(function (c) {
c.addEventListener("change", syncParent);
});
syncParent();
</script>
</body>
</html>Marque uma das caixas filhas: o checkbox "Select all" torna-se indeterminado e o contorno verde aparece. Marque os três: o contorno desaparece e ele muda para o estado totalmente marcado.
Exemplo: um grupo de radio indeterminado
Um grupo de radio está no estado indeterminado enquanto nenhuma de suas opções estiver selecionada. A pseudo-classe :indeterminate corresponde a cada <input type="radio"> no grupo até que o usuário escolha uma resposta. Assim que qualquer opção for escolhida, todo o grupo sai do estado indeterminado e a estilização é removida.
Isso é útil para incentivar os usuários a fazer uma escolha — por exemplo, você pode usá-la na validação de formulários junto com :invalid e :valid para orientar visualmente os usuários a perguntas obrigatórias não respondidas.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
label {
margin-right: .5em;
position: relative;
top: 1px;
}
input[type="radio"]:indeterminate + label {
color: #8ebf42;
}
</style>
</head>
<body>
<h2>:indeterminate selector example</h2>
<form>
<input type="radio" name="option" value="yes" id="yes" />
<label for="yes">Yes</label>
<input type="radio" name="option" value="no" id="no" />
<label for="no">No</label>
<input type="radio" name="option" value="dont-know" id="dont-know" />
<label for="dont-know">Don’t know</label>
</form>
</body>
</html>Exemplo: uma barra de progresso indeterminada
Um elemento <progress> sem atributo value não tem percentual de conclusão conhecido, então corresponde a :indeterminate. Os navegadores renderizam uma barra animada de "carregando" por padrão. Adicionar um atributo value (e opcionalmente max) move o elemento para o estado determinado e a regra CSS deixa de ser aplicada.
<!DOCTYPE html>
<html>
<head>
<title>Indeterminate progress</title>
<style>
progress:indeterminate {
opacity: 0.6;
width: 200px;
}
/* Once a value is set, show a green accent */
progress:not(:indeterminate) {
accent-color: #2a9d8f;
width: 200px;
}
</style>
</head>
<body>
<p>Indeterminate (no value): <progress></progress></p>
<p>Determinate (value set): <progress value="60" max="100"></progress></p>
</body>
</html>A propriedade accent-color controla a cor de preenchimento de <progress> nos navegadores que a suportam (Chrome 93+, Firefox 92+, Safari 15.4+). Para suporte a navegadores mais antigos, pode ser necessário usar pseudo-elementos com prefixo de fornecedor, como ::-webkit-progress-bar e ::-moz-progress-bar, mas estes não fazem parte da especificação CSS padrão.
Combinando com outras pseudo-classes
:indeterminate pode ser encadeada com outras pseudo-classes de estado para criar seletores precisos:
/* Indeterminate checkbox that is also focused */
input[type="checkbox"]:indeterminate:focus {
outline: 3px solid royalblue;
}
/* Indeterminate and disabled checkbox — show a muted style */
input[type="checkbox"]:indeterminate:disabled {
opacity: 0.4;
cursor: not-allowed;
}Veja :focus, :disabled e :enabled para mais detalhes sobre essas pseudo-classes.
Acessibilidade
O sinalizador indeterminado é puramente visual no nível do CSS; ele não altera o valor enviado com o formulário. Um checkbox tri-estado ainda é enviado como marcado ou desmarcado, dependendo do estado atual de checked.
Para tecnologia assistiva, você deve expor explicitamente o terceiro estado usando o atributo aria-checked="mixed" no controle mestre. Sem ele, os leitores de tela anunciam o controle simplesmente como marcado ou desmarcado, e os usuários que dependem de AT não saberão o significado da seleção parcial.
<!-- Accessible tri-state master checkbox -->
<input
type="checkbox"
id="all"
aria-checked="mixed"
aria-label="Select all items"
/>Mantenha aria-checked em sincronia com a propriedade indeterminate em seu JavaScript:
function syncParent() {
var checked = [...children].filter(function (c) { return c.checked; }).length;
if (checked === 0) {
all.indeterminate = false;
all.checked = false;
all.setAttribute("aria-checked", "false");
} else if (checked === children.length) {
all.indeterminate = false;
all.checked = true;
all.setAttribute("aria-checked", "true");
} else {
all.indeterminate = true;
all.checked = false;
all.setAttribute("aria-checked", "mixed");
}
}Para grupos de radio :required onde nenhuma opção foi escolhida, considere também usar aria-required="true" em cada input para que a tecnologia assistiva possa identificar o grupo sem resposta.
Suporte dos navegadores
A pseudo-classe :indeterminate é suportada em todos os navegadores modernos (Chrome, Edge, Firefox, Safari). Os três tipos de elementos — checkboxes, grupos de radio e barras de progresso — são correspondidos nas versões atuais dos navegadores.
| Elemento | Notas |
|---|---|
input[type="checkbox"]:indeterminate | Suportado em todos os navegadores modernos. Requer JS para definir a propriedade indeterminate. |
input[type="radio"]:indeterminate | Suportado em todos os navegadores modernos. Aplicado automaticamente até que o usuário selecione uma opção. |
progress:indeterminate | Suportado em todos os navegadores modernos. Aplicado automaticamente quando o atributo value está ausente. |