Formulários

Design Systemtokens.css, base.css, layouts.css, comum.jsAtualizado em 27 out 2026

Nenhum controle com a cara do navegador. Todos no visual da marca.

Campo, lista, data, caixa, chave e arquivo são desenhados pelo DS. Parte deles precisa do comum.js carregado: ele acende o brilho do campo, desenha a lista do select, o calendário e a gota da chave. Cada exemplo está ao vivo; abra Código para copiar o HTML exato.

Campo de texto

.campo7 estados

Rótulo em cima, campo de 44px, raio 12, borda Tinta 14%. Em foco o campo acende: fica branco, a borda vira Bruma Profunda e o brilho da marca gira atrás dele.

Todos os estados

.campo · .dica · .erro · disabled · readonly

O <label class="campo"> envolve o texto do rótulo e o input: o rótulo já fica associado, sem for. A ajuda é a .dica; o erro é o .erro, só no texto, em vermelho semântico.

Foco: o brilho

.brilho

Degradê cônico só em tons claros da Bruma (Bruma Clara → Bruma Profunda → Bruma → Aço), desfoque 7px, girando em 5s enquanto o campo tem foco. O comum.js envolve o input num <span class="brilho">; sem ele, não há brilho. Clique no outro campo.

Texto longo

.campo textarea

Mesmo visual, altura pelas linhas (rows), redimensiona na vertical, rola sem barra. Também ganha o brilho.

Rótulo com for

div.campo > label[for]

Quando o .campo guarda mais de um controle (ou um combo), ele vira <div> e o <label for> aponta para o id do controle.

Busca

.busca2

Campo com lupa à esquerda e o mesmo brilho no foco, sem precisar do comum.js (o brilho está no próprio .busca). Translúcida na barra superior; Tela dentro de cartão.

Na barra superior

.busca

Branco 60% + borda embutida, 44px, 280px de largura (até 460 na barra).

Dentro de cartão

.cartao .busca

Fundo Tela para aparecer sobre o branco.

Estados

:focus

Em foco: fundo branco + brilho girando.

Repouso
Em foco

Lista de escolha

select[data-combo] · .combo-botao3

Você escreve um <select data-combo> comum. O comum.js esconde o select e desenha no lugar um botão .combo-botao e uma lista .popover.combo-lista em vidro. O select continua guardando o valor e disparando change. Formulário montado por JS (editar/criar na hora): chame window.combo(select) depois de pôr o select na página. Select nativo à vista, nunca.

Dentro de um campo

.campo select[data-combo]

No .campo o botão tem 44px e largura toda, igual ao campo de texto. Clique para abrir.

Solta (filtro, ordem)

select[data-combo]

Fora do .campo: 36px, no mínimo 190px. Para filtros e ordenação acima de listas.

Estados do botão da lista

.combo-botao · :hover · .aberto · .combo-item.escolhido

Fechado: borda Tinta 14%, seta 14px. Hover: borda Tinta 46%. Aberto: borda Ardósia Média + anel de foco, seta virada; a opção atual em Bruma Clara. Desabilitado: disabled no select passa para o botão (45%, cursor proibido). Teclado: ↓/↑ no botão abrem no item escolhido; na lista, ↓/↑, Home/End, Enter escolhe, Esc fecha.

Fechado
Hover
Desabilitado

Data

.campo-data · .calendario2

Nunca o <input type="date"> do navegador. O campo é somente leitura com data-data; ao clicar, o comum.js desenha o calendário em vidro: português, semana começando no domingo, hoje com anel, dia escolhido em disco Ardósia, rodapé Limpar | Hoje.

Campo de data

.campo.campo-data input[data-data]

Ícone de calendário à esquerda (16px). Valor no formato dd/mm/aaaa. Abre com clique ou Enter, espaço ou ↓ (foca o dia escolhido ou hoje; Tab anda pelos dias); Esc ou clique fora fecham. O ícone fica por cima do brilho.

O calendário aberto

.calendario

292px, raio 16, vidro denso. Dias de 34px em círculo; dias de fora do mês em Tinta 32%.

Outubro de 2026
DSTQQSS

Caixa e radio

input[type=checkbox] · input[type=radio] · .opcao2

18px, borda Tinta 24%. Marcado em --marcado: Ardósia no claro, Lima no escuro. Sempre dentro de um <label class="opcao">: o texto inteiro é clicável.

Caixa de marcar

input[type=checkbox]

Cantos 6px; marcada com check branco (traço 3 desenhado a 12px = 1,5px na tela). Indeterminada (parte do grupo marcada) = traço branco: a tela liga com el.indeterminate = true.

Avisos

Opção única

input[type=radio]

Círculo; marcado = miolo Ardósia com anel branco de 4px por dentro. Mesmo name no grupo.

Visibilidade

Estados

:hover · :checked · :indeterminate · :focus-visible · :disabled

Hover: borda Tinta 46%. Foco do teclado: anel Bruma Profunda. Desabilitado: 45%.

Vazia
Hover
Marcada
Indeterminada
Foco
Desabilitada
Radio vazio
Radio marcado
Radio foco

Chave líquida e opção

.chave · .gota · .opcao2

Liga/desliga de 40 × 22. Ao trocar, o botão atravessa o trilho esticando como uma gota e uma gotinha vai atrás e se funde a ele (filtro SVG "gooey", 420ms, sem quique). A camada .gota é criada pelo comum.js. Clique para ver.

Chave

.chave

Trilho Tinta 15%; ligada = Ardósia (Lima no escuro). O input fica invisível por cima de tudo; o .trilho desenha o fundo. Sempre com rótulo.

Rótulo + chave à direita

.opcao > .texto + .chave

Padrão das telas de configurações: o texto à esquerda, a chave encostada à direita (.opcao .chave:last-child ganha margin-left: auto e order: 1: mesmo com o texto solto depois da chave, ela fica à direita). Prefira o texto num <span class="texto">.

Estados

:checked · :focus-visible · :disabled

Foco do teclado: anel no trilho. Sem o comum.js a chave ainda funciona: o botão só desliza (sem gota).

Desligada
Ligada
Foco
Desabilitada

Deslizador

input[type=range].deslizador1

Trilho de 6px em pílula, parte preenchida em --marcado, botão branco de 16px com borda. O preenchimento vem da variável --valor, que o comum.js atualiza ao arrastar (28/10/2026).

Deslizador

.deslizador + --valor

O comum.js escreve --valor ao carregar e a cada input: o preenchimento acompanha o botão no Chrome e no Safari (no Firefox ele já seguia sozinho). Nada de style no HTML.

Arquivo

.zona2

Área tracejada de soltar arquivo, com o <input type="file"> escondido dentro. Nunca o botão nativo "Escolher arquivo". Ao arrastar por cima, o comum.js põe .sobre (realce).

Zona de arquivo

label.campo > .zona

O <label> em volta faz o clique abrir a escolha de arquivo. Diga o tipo e o tamanho aceitos. Dentro do .campo o texto da zona fica em tinta (não herda o cinza do rótulo).

Arrastando por cima

.zona.sobre

Fundo Bruma 35% e borda --acento. O mesmo realce aparece no hover.

Solte para enviar PDF até 10 MB

Formulário completo

Tudo junto, num cartão, com validação visual: o e-mail está em erro e a descrição tem ajuda. Ações no pé: Cancelar fantasma e Salvar botão, à direita.

Novo processo

.cartao > form

Duas colunas no computador, uma abaixo de 1024px. O DS não valida sozinho: a tela confere e mostra o .erro embaixo do campo.

Novo processo

Os campos com erro mostram o que falta embaixo deles.
Visibilidade
Avisos

Rótulo, ajuda e erro

3

Três textos em volta de cada campo, cada um com um papel e uma cor.

TextoClasseVisualRegra
Rótulo.campo (texto do label)Inter 12px, --tinta-46, 6px acima do campoSempre visível, em cima, curto (2 a 4 palavras), sem dois-pontos
Ajuda.dica11,5px --tinta-46, ícone i-info 13px, 10px abaixoO que a pessoa precisa saber antes de escrever: formato, limite, onde aparece
Erro.campo .erro11,5px --negativo #A8353ADiz como resolver, não só o que deu errado. Só o texto fica vermelho
Exemplo no campoplaceholderTinta 46%Exemplo de formato (nome@impulsamos.es), nunca no lugar do rótulo
Faça
  • Rótulo em cima de todo campo, mesmo quando o placeholder parece bastar.
  • Erro em vermelho semântico só no texto, logo abaixo do campo, dizendo como corrigir.
  • Lista, data, caixa, chave e arquivo sempre no visual do DS, com o comum.js carregado.
  • Confirmação de perigo numa .janela.
Não faça
  • Campo sem rótulo, ou placeholder fazendo papel de rótulo.
  • Borda ou fundo vermelho berrante no campo; anel de foco de outra cor.
  • Select nativo, type="date", checkbox azul do sistema, botão "Escolher arquivo".
  • alert(), confirm(), prompt().

Acessibilidade

3

Três garantias em todo formulário.

  1. Rótulo associado. O <label class="campo"> envolve o controle, ou o <label for> aponta para o id. Controle sem texto visível (busca, chave solta) leva aria-label. Erro e ajuda ligados ao campo por aria-describedby; campo com erro com aria-invalid="true".
  2. Foco visível. Campo de texto e busca: o brilho no lugar do anel. Caixa, radio, chave e botão da lista: o anel --sombra-foco (Bruma Profunda 4px; Lima 3px no escuro). Nunca tire o foco sem pôr um dos dois.
  3. Área de toque. Campos e lista no .campo têm 44px. Caixa e radio têm 18px, por isso vão num .opcao: o texto inteiro é clicável. A chave (40 × 22) também vai num label. Desabilitado usa o atributo disabled (45% e cursor proibido).
Teclado (28/10/2026): a lista do select[data-combo] abre com Enter/espaço ou ↓/↑ e anda pelas setas (Home/End nas pontas); o calendário abre com Enter, espaço ou ↓; os dois fecham com Esc. Um select com disabled desabilita o botão desenhado, também se mudar depois.

O que o comum.js faz

Design System/comum.js

Sem ele, metade dos controles fica sem efeito ou com a cara do navegador. Carregue no fim do <body>, depois do conteúdo: ele age uma vez, nos elementos que já existem.

ControleO que o comum.js injetaSem o comum.js
.campo input, .campo textareaEnvolve cada um num <span class="brilho"> (menos checkbox, radio, range, file e hidden)Foco sem brilho: só a borda Bruma Profunda
select[data-combo]Esconde o select e cria div.combo com button.combo-botao (aria-haspopup="listbox", aria-expanded) e div.popover.combo-lista[role=listbox] com um button.combo-item[role=option] por opção; marca .escolhido; dispara change no select; Esc e clique fora fecham; ↓/↑ abrem e andam pela lista, Home/End; copia o disabled do select para o botão (e acompanha mudanças). data-html na option põe HTML no item. Opções trocadas depois: dispare o evento opcoes no selectSelect nativo do navegador
.campo-data input[data-data]Cria o div.calendario dentro do .campo-data, abre no clique ou com Enter/espaço/↓, monta 42 dias (domingo primeiro), .fora, .hoje, .escolhido, setas de mês, Limpar e Hoje; escreve dd/mm/aaaa e dispara changeCampo somente leitura que não abre nada
.chaveCria a camada span.gota (botão + gotinha com o filtro gooey) e põe .tocada na primeira troca, para a gota só esticar depois do primeiro toqueO botão só desliza no trilho
input[type=range].deslizadorEscreve --valor (em %) ao carregar e a cada inputPreenchimento parado em 50% (Chrome/Safari)
.zonaPõe e tira .sobre ao arrastar por cima (dragenter, dragover, dragleave, drop)Sem realce ao arrastar
avisar(texto, icone)Aviso flutuante depois de salvar (some em 5s)Função não existe

Modo escuro

Ligue no botão de tema da lateral para ver esta página no escuro. O que muda:

ControleNo escuro
CampoFundo --branco escuro #1A2C3A; foco com borda Aço; brilho em Ardósia e Aço com um fio de Lima
BuscaTela 6%; em foco borda embutida --linha-forte
Caixa e radioBorda Tela 30% (hover 55%); marcado em Lima com check Tinta
ChaveTrilho Tela 16%; ligada = Lima com a gota Tinta
DeslizadorPreenchimento Lima; botão Lima com borda Tinta
Lista, calendárioVidro denso escuro; dia escolhido Lima com número Tinta
ZonaBruma 4% com borda Bruma 22% (arrastando: 8%)
Erro--negativo clareado (#D8989A), legível no escuro