Button
Recipe React distribuída como source, com comportamento Base UI e classes/tokens públicos do Button TIS.
Design
Preview funcional
Executado pela recipe React distribuída via shadcn e baseada em Base UI.
Abrir playground React · shadcn/Base UI
Estilos
Anatomia
2 Icon (opcional) — frame/ícone 20px no sm e 24px no md/lg.
3 Label (
.ds-button__label) — tipografia e cor via Component tokens.4 Padding raiz — sm 8×8px, md 10×12px, lg 12×16px.
5 Padding do label — 4px adicionais no Label Frame para equilíbrio óptico.
Tamanhos
| Size | Altura | Fonte | Padding | Touch target |
|---|---|---|---|---|
Small (--sm) | 32px (component.button.height.sm) | component.button.label.font-size.sm | 8×8px (component.button.padding-y.sm × padding-x.sm) | 32px — meets WCAG 2.5.8 min (24px) |
Medium (--md) | 40px (component.button.height.md) | component.button.label.font-size.md | 10×12px (component.button.padding-y.md × padding-x.md) | 40px |
Large (--lg) | 48px (component.button.height.lg) | component.button.label.font-size.lg | 12×16px (component.button.padding-y.lg × padding-x.lg) | 48px — meets AAA 44px target |
Estados
Estados são controlados via pseudo-classes CSS (:hover, :active, :focus-visible, [disabled]), não classes modificadoras.
| Estado | CSS trigger | Mudança visual | Token |
|---|---|---|---|
| Default | — | Preenchimento primário | component.button.bg.brand.default |
| Hover | :hover | Preenchimento mais escuro | component.button.bg.brand.hover |
| Pressed | :active | Preenchimento mais escuro ainda | component.button.bg.brand.pressed |
| Focus | :focus-visible | Ring de 2px com afastamento de 2px e cores do estado focus | component.button.bg.brand.focus, component.button.content.color.brand.focus, component.button.focus-ring.* |
| Disabled | [disabled] | Bg + conteúdo atenuados, sem pointer events | component.button.bg.brand.disabled, component.button.content.color.brand.disabled |
Com ícone
Somente ícone
Carregamento
Largura total
Mapeamento de tokens
Tokens consumidos pela variante Brand. Outras variantes seguem o mesmo padrão usando seus respectivos grupos de cor.
| Propriedade | Token (Component) | Variável CSS |
|---|---|---|
| height (sm) | component.button.height.sm | --ds-button-height-sm |
| height (md) | component.button.height.md | --ds-button-height-md |
| height (lg) | component.button.height.lg | --ds-button-height-lg |
| min-width (sm/md/lg) | component.button.min-width.{sm,md,lg} | --ds-button-min-width-* |
| padding-x (sm/md/lg) | component.button.padding-x.{sm,md,lg} | --ds-button-padding-x-* |
| padding-y (sm/md/lg) | component.button.padding-y.{sm,md,lg} | --ds-button-padding-y-* |
| gap (sm/md/lg) | component.button.gap.{sm,md,lg} | --ds-button-gap-* |
| radius / border-width | component.button.radius.default, component.button.border-width.default | --ds-button-radius-default, --ds-button-border-width-default |
| bg por estilo/estado | component.button.bg.{brand,toned,outline,ghost,success,danger}.* | --ds-button-bg-* |
| border color Outline | component.button.border-color.outline.* | --ds-button-border-color-outline-* |
| text/icon color | component.button.content.color.{style}.{state} | --ds-button-content-color-* |
| label typography | component.button.label.{font-size,line-height,font-weight,letter-spacing}.* | --ds-button-label-* |
| icon frame/size | component.button.icon.size.{sm,md,lg}, component.button.icon.stroke-width.{sm,md,lg} | --ds-button-icon-* |
| icon-only | component.button.icon-only-{width,padding}.{sm,md,lg} | --ds-button-icon-only-* |
| focus ring | component.button.focus-ring.radius.default, component.focus-ring.{width,color.default,color.success,color.error} | --ds-focus-ring-* + --ds-button-focus-ring-radius-default |
Variante Toned
--ds-toned-background-default, --ds-toned-background-hover, --ds-toned-background-active) em vez de preenchimentos opacos. Isso difere dos padrões Subtle/Muted que usam tokens de background opacos. A abordagem translúcida permite que o button Toned se adapte naturalmente a qualquer cor de superfície abaixo dele, mantendo um tint de marca consistente.
Figma
O componente Figma expõe as propriedades abaixo no painel. Booleans de visibilidade ficam imediatamente acima do slot que controlam.
| Propriedade | Tipo | Padrão | Opções |
|---|---|---|---|
| Estilo | Variant | Brand | Brand, Toned, Outline, Ghost, Success, Danger |
| Tamanho | Variant | Medium | Small (32px), Medium (40px), Large (48px) |
| Estado | Variant | Default | Default, Hover, Pressed, Focused, Disabled |
| Icon Only | Variant | false | Default (com label), Icon Only (quadrado) |
| Loading | Boolean | false | true, false |
| Show Left Icon | Boolean | false | Alterna a visibilidade do frame de ícone esquerdo |
| Left Icon | Instance swap | Placeholder | Define o componente de ícone esquerdo |
| Show Right Icon | Boolean | false | Alterna a visibilidade do frame de ícone direito |
| Right Icon | Instance swap | Placeholder | Define o componente de ícone direito |
Uso
Quando usar
<a>). Não use buttons para ações inline de texto ou quando o peso visual competiria com a ação principal da página.
| Estilo | Usar para | Ênfase |
|---|---|---|
| Brand | Ação principal da página. Um por seção, idealmente um por página. | Máxima |
| Toned | Ações secundárias que precisam de visibilidade mas não devem competir com Brand. | Média |
| Outline | Ações secundárias ou terciárias. Combina bem ao lado de um button Brand. | Média |
| Ghost | Ações terciárias, ações de toolbar ou buttons de fechar/dispensar. | Baixa |
| Success | Confirmar um resultado positivo: aprovar, concluir, publicar. | Contextual |
| Danger | Ações destrutivas: excluir, remover, revogar. Sempre requer confirmação. | Contextual |
Boas práticas
Diretrizes de conteúdo
| Regra | Exemplo |
|---|---|
| Use verbo + substantivo para clareza | "Save changes", "Add item", "Delete project" — não apenas "Submit" ou "OK" |
| Use sentence case | "Save changes" — não "Save Changes" ou "SAVE CHANGES" |
| Mantenha labels curtos (1–3 palavras) | "Export CSV" — não "Click here to export your data as CSV" |
| Seja específico sobre ações destrutivas | "Delete account" — não "Delete" ou "Remove" |
| Evite labels genéricos | "Confirm order" — não "Click here" ou "Yes" |
Buttons somente-ícone precisam de aria-label | aria-label="Close dialog" — descreve a ação, não o ícone |
Composição React
import { Button } from "@/components/ui/button"
<Button type="submit">Salvar alterações</Button>Implementação
- Status
- Beta
- Distribuição
- Source via shadcn
Instalação
Configure o namespace uma única vez na integração React.
npx shadcn@latest add @tis/buttonpnpm dlx shadcn@latest add @tis/buttonyarn dlx shadcn@latest add @tis/buttonbunx --bun shadcn@latest add @tis/buttonContrato público
- Item do registry
@tis/button- Provider
- Base UI
- Distribuição
- Source copiado para a aplicação
- Status
- Beta
Acessibilidade
Interação por teclado
| Tecla | Ação |
|---|---|
Tab | Move o foco para o button (ou além dele se desabilitado) |
Enter | Ativa o button |
Space | Ativa o botão |
Buttons desabilitados ([disabled]) são removidos da ordem de tabulação automaticamente pelo navegador. Buttons em carregamento também devem definir aria-disabled="true" para prevenir interação enquanto preservam a ordem de tabulação.
Acessibilidade
| Critério WCAG | Requisito | Status |
|---|---|---|
| 2.4.11 Focus Appearance (AA) | Focus ring 2px + gap de 2px, contraste ≥ 3:1 contra cores adjacentes | ✓ |
| 2.5.8 Target Size min (AA) | Menor tamanho (32px) excede o mínimo de 24px | ✓ |
| 2.5.5 Target Size (AAA) | Tamanho grande (48px) atende ao alvo de toque de 44px | ✓ |
| 1.4.3 Contrast (AA) | Texto branco sobre Brand/Danger fill ≥ 4.5:1. Desabilitado isento. | ✓ |
| 4.1.2 Name, Role, Value (A) | Use o elemento <button>. Somente-ícone requer aria-label. | ✓ |
| 1.4.1 Use of Color (A) | Estado focado tem ring visível. Desabilitado tem texto esmaecido + opacidade reduzida. | ✓ |
aria-label — obrigatório em buttons somente-ícone.aria-disabled="true" + aria-busy="true" — definido em buttons em carregamento.disabled — use o atributo nativo para buttons realmente desabilitados (removidos da ordem de tabulação).
Responsabilidade da saída
Preserve a semântica da Base UI e teste conteúdo real, foco visível e nomes acessíveis na aplicação consumidora.
Evidência de validação
Coberta pelo Storybook da saída independente e por verificações de browser, responsividade, teclado, Axe e bundle.