UaiUI

Sistema de design com bordas retas, sombras duras e temas por tokens. Cada componente tem preview, código e requisitos de acessibilidade.

Densidade

Button

Dispara uma ação: salvar, exportar, aplicar, abrir um diálogo.

Instalação

  1. Importe uaiui-ds/tokens-wrapper.css e coloque os componentes dentro do wrapper .uaiui (veja Tokens e temas).
  2. Importe uaiui-ds/components/button.css. O código abaixo é o conteúdo desse arquivo.
/* button: type (filled | outlined | ghost) × style (primary | secondary | danger). */
.uai-button {
  --_bg: var(--interface-function-primary-normal-background);
  --_fg: var(--interface-function-primary-normal-txtOn);
  --_bg-hover: var(--interface-function-primary-action-background);
  --_fg-hover: var(--interface-function-primary-action-txtOn);
  --_bg-press: var(--interface-function-primary-active-background);
  --_fg-press: var(--interface-function-primary-active-txtOn);
  --_border: var(--button-border);

  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--button-gap);
  min-height: var(--button-min-height);
  padding: var(--button-padding-y) var(--button-padding-x);
  border: var(--border-width-default) solid var(--_border);
  border-radius: var(--radius-control);
  background: var(--_bg); color: var(--_fg);
  box-shadow: var(--shadow-offset-component) var(--shadow-offset-component) 0 0 var(--button-shadow-color);
  font: var(--font-weight-label) var(--button-label-font-size)/var(--button-label-line-height) var(--font-family-label), monospace;
  text-transform: var(--font-transform-label);
  cursor: pointer; text-decoration: none;
  transition: background-color var(--motion-duration-press), color var(--motion-duration-press), box-shadow var(--motion-duration-press), transform var(--motion-duration-press);
}
.uai-button svg { width: var(--button-icon-size); height: var(--button-icon-size); flex: none; }
.uai-button:hover { background: var(--_bg-hover); color: var(--_fg-hover); box-shadow: var(--shadow-offset-component-hover) var(--shadow-offset-component-hover) 0 0 var(--button-shadow-color); transform: translateY(-2px); }
.uai-button:active { background: var(--_bg-press); color: var(--_fg-press); box-shadow: none; transform: translateY(1px); }
.uai-button:focus-visible { outline: var(--focus-ring-width) solid var(--ui-focus-ring); outline-offset: var(--focus-ring-offset); }

.uai-button[data-style="secondary"] {
  --_bg: var(--interface-function-secondary-normal-background); --_fg: var(--interface-function-secondary-normal-txtOn);
  --_bg-hover: var(--interface-function-secondary-action-background); --_fg-hover: var(--interface-function-secondary-action-txtOn);
  --_bg-press: var(--interface-function-secondary-active-background); --_fg-press: var(--interface-function-secondary-active-txtOn);
}
.uai-button[data-style="danger"] {
  --_bg: var(--interface-function-error-normal-background); --_fg: var(--interface-function-error-normal-txtOn);
  --_bg-hover: var(--interface-function-error-action-background); --_fg-hover: var(--interface-function-error-action-txtOn);
  --_bg-press: var(--interface-function-error-active-background); --_fg-press: var(--interface-function-error-active-txtOn);
}
.uai-button[data-type="outlined"] {
  --_bg: var(--button-outlined-normal-background); --_fg: var(--button-outlined-normal-txtOn);
  --_bg-hover: var(--button-outlined-action-background); --_fg-hover: var(--button-outlined-action-txtOn);
  --_bg-press: var(--button-outlined-active-background); --_fg-press: var(--button-outlined-active-txtOn);
}
.uai-button[data-type="ghost"] {
  --_bg: var(--interface-function-ghost-normal-background); --_fg: var(--interface-function-ghost-normal-txtOn);
  --_bg-hover: var(--interface-function-ghost-action-background); --_fg-hover: var(--interface-function-ghost-action-txtOn);
  --_bg-press: var(--interface-function-ghost-active-background); --_fg-press: var(--interface-function-ghost-active-txtOn);
  border-color: transparent; box-shadow: none; padding-inline: 0;
}
.uai-button[data-type="ghost"]:hover, .uai-button[data-type="ghost"]:active { box-shadow: none; transform: none; }
.uai-button:disabled, .uai-button[aria-disabled="true"] {
  background: var(--interface-function-disabled-normal-background); color: var(--interface-function-disabled-normal-txtOn);
  border-color: var(--interface-function-disabled-normal-border); box-shadow: none; transform: none; cursor: not-allowed;
}
.uai-button[data-type="ghost"]:disabled { background: transparent; border-color: transparent; }

/* icon button: mesmo conjunto de cores, quadrado do tamanho mínimo do botão. */
.uai-icon-button {
  display: inline-grid; place-items: center;
  width: var(--icon-button-size); height: var(--icon-button-size); padding: 0;
}
.uai-icon-button svg { width: var(--icon-button-icon-size); height: var(--icon-button-icon-size); stroke-width: var(--icon-button-icon-weight); }
@media (prefers-reduced-motion: reduce) { .uai-button { transition: none; } }

Uso

<button class="uai-button" data-type="filled" data-style="primary">Salvar</button>

Quando usar. filled primary: a ação principal da área, no máximo uma por área. filled secondary: ação principal num contexto da segunda cor do tema. filled danger: ação que apaga ou não dá para desfazer; peça confirmação num modal. outlined: ações secundárias ou frequentes. ghost: ações de baixo peso, como Redefinir e Ajuda.

Quando não usar. Para ir a outra página, use link. Para ligar e desligar uma opção, use toggle button. Para ação só com ícone, use o botão de ícone abaixo.

Exemplos

Desabilitado

Sem sombra, em cinza, e o cursor indica que não dá para clicar.

Com ícone

O ícone herda a cor do texto e muda de tamanho com a densidade (24, 24 e 20).

Botão de ícone

Quadrado, com a altura do botão (54, 46 e 44). O rótulo vai em aria-label e o ícone é aria-hidden.

Props

Props do button
PropValoresPadrãoDescrição
data-typefilled | outlined | ghostfilledPeso visual. filled tem fundo cheio; outlined fundo da página; ghost sem borda nem sombra.
data-styleprimary | secondary | dangerprimaryCor do filled: marca, segunda cor do tema ou ação destrutiva. Não existe em outlined e ghost.
disabledbooleanfalseEstado desabilitado. Use aria-disabled="true" quando o botão precisar continuar na ordem de Tab.
aria-labelstring—Obrigatório no botão só de ícone. Texto específico: "Fechar janela", não só "Fechar".

A tabela rola na horizontal; a região recebe foco pelo teclado.

Combinação inválida: data-style="secondary" ou "danger" com outlined ou ghost.

Movimento e foco

  • No hover, o botão sobe 2 px e a sombra vai de 2 para 4 px.
  • No pressed, o botão desce 1 px e a sombra some.
  • Transição de 100 ms; sem transição com prefers-reduced-motion.
  • Anel de foco: 2 px de espessura e 2 px de afastamento (outline e outline-offset).

Acessibilidade

  • Use o elemento <button>. Enter e Espaço ativam.
  • Botão só de ícone precisa de aria-label específico, e o ícone leva aria-hidden="true".
  • Área de toque de pelo menos 44 × 44 px em todas as densidades (altura mínima: 54, 46 e 44 px).
  • O estado nunca depende só de cor: o desabilitado também perde a sombra.