Button

Ação rotulada. Três variantes de ênfase, dois tamanhos, quatro estados. A variante primary materializa-se como Tecla V-B.

Abrir no Storybook ↗

Quando usar

Para toda ação direta do usuário: confirmar pagamento, cancelar, voltar, abrir, enviar. Ações rotineiras e ações de alta consequência.

Quando não usar

  • Para ação de filtro pontual numa listagem curta — usar Chip se o filtro for representado como etiqueta.
  • Para separar dois blocos de conteúdo — usar Hairline ou espaçamento.
  • Para texto inline que leva a outro contexto — usar link textual (não coberto na v1).

Anatomia

A variante primary é a única com três camadas físicas: socket, rim e cap. As variantes secondary e tertiary são de camada única.

Slots comuns a todas as variantes:

  • label — string curta, verbo direto ("Pagar agora", "Ver depois", "Cancelar").
  • iconLeading (opcional) — glifo 16/24 à esquerda.
  • iconTrailing (opcional) — glifo 16/24 à direita.

Variantes

VarianteÊnfaseMaterializaçãoUso
primaryAltaTecla V-B (socket + rim + cap)Ação-chave da cena. Uma por tela, no máximo duas.
secondaryMédiaSólido V-A (preto convencional)Ação alternativa relevante.
tertiaryBaixaGhost V-A (fundo transparente, hover preenche)Ação secundária, cancelar, ver mais.
primary · lg
secondary · md
tertiary · md

Tamanhos

SizeAlturaUso
md40 pxDefault — contextos de UI padrão.
lg64 px (secondary / tertiary) · 65 px (primary / Tecla)Contexto em que o botão domina a cena: onboarding, landing, card-ação.
primary · lg (65 px)
primary · md (40 px)
secondary · md (40 px)
secondary · lg (64 px)
tertiary · md (40 px)
tertiary · lg (64 px)

Estados

Estados demonstrados na variante secondary. Hover e active são estados de runtime — renderizados aqui como classes de demonstração estática.

default
hover
active
disabled
loading

Estados — primary (Tecla)

A Tecla cobre cinco estados visuais: rest, hover, active (pressed), disabled e loading. Apresentação visual derivada da iteração-fonte do Claude Design (Variante B canônica do merge). Hover troca os tokens do cap por --color-accent-amber-hover-*; disabled neutraliza o acento V-B com --color-accent-amber-disabled-*. Active (pressed) mantém --shadow-tecla-pressed. Loading preserva o cap âmbar vivo (sobrescreve disabled mesmo quando coexistem) e substitui o label por um spinner geométrico — paralelo ao padrão do secondary, mas com classe própria .peppe-tecla__spinner pra preservar isolamento entre os dois CSS canônicos.

rest
hover
active (pressed)
disabled
loading

Estados — tertiary

O tertiary herda a estrutura do secondary mas com fundo transparente em repouso. O hover preenche o fundo com --color-nav-hover (3% ink-primary) — transição suave via --duration-micro. Active usa --color-nav-active (5%). Disabled mantém apenas a cor de rótulo desativada.

default
hover
active
disabled

Playground

Teclas reais e interativas. Hover passa o mouse, click executa pressed via :active, e o toggle de disabled liga/desliga o estado disabled na tecla principal. Use o DevTools pra inspecionar propriedades computadas em cada estado.

primary · lg (real button)
primary · md (real button)
Entrar pra filaprimary · lg (anchor)
Cliques na tecla lg: 0

Nota técnica: O playground usa elementos <button> e <a> reais. Estados runtime (:hover, :active, :focus-visible, :disabled) são acionados pela própria interação do usuário. Os modifiers BEM (--hover, --pressed, --disabled) usados nas amostras de Estados existem em paralelo pra demos estáticas — ambos os caminhos disparam as mesmas regras CSS.

Tokens aplicáveis

TokenValorPapel
--color-accent-rim#5F0000Rim borgonha da Tecla
--color-accent-amber-top#F7692BCap âmbar — topo (rest)
--color-accent-amber-bottom#FA4C00Cap âmbar — base (rest)
--color-accent-amber-hover-top#FF986BCap — topo hover
--color-accent-amber-disabled-top#C9C9C9Cap — disabled
--shadow-teclaSombra do socket (rest)
--shadow-tecla-pressedinset 0 4px 8px rgba(0,0,0,0.2), inset 0 1px 2px rgba(95,0,0,0.45)Sombra interna (active) — duas camadas: profundidade do "afundou" + reforço curto do rim borgonha
--radius-tecla-socket18pxRaio do socket
--radius-tecla-rim16pxRaio do rim
--radius-tecla-cap12pxRaio do cap
--color-ink-primary#171717Secondary — fundo (rest)
--color-ink-primary-hover#2A2A2ASecondary — fundo (hover)
--color-ink-primary-active#000000Secondary — fundo (active)
--color-ink-inverse#F7F7F7Secondary — label sobre o preto
--color-nav-hoverrgba(23,23,23,0.03)Tertiary — fundo (hover)
--color-nav-activergba(23,23,23,0.05)Tertiary — fundo (active)
--radius-button-md12pxSecondary / tertiary — raio tamanho md (40px)
--radius-button-lg20pxSecondary / tertiary — raio tamanho lg (64px)
--type-family-sansInstrument SansLabel de todas as variantes
--type-size-md16pxTamanho do label
--type-weight-medium500Peso do label

Conteúdo

  • Label é verbo direto e específico. "Pagar agora", não "Clique aqui". "Confirmar pagamento", não "OK".
  • Máximo 3 palavras. Se não couber, a ação está mal delimitada.
  • Sem pontuação final. O botão é ação, não frase.
  • Sem emoji. A única exceção é iconLeading ou iconTrailing com função semântica real.

Ver Voz & Tom §4.3 — densidade e extensão.

Acessibilidade

  • aria-label obrigatório quando o botão tem apenas ícone (sem label visível).
  • Foco navegável com ring visível — delegado ao token --focus-ring-width e --focus-ring-offset.
  • Contraste: label branco sobre cap âmbar passa WCAG AA em md; secondary --color-ink-inverse (#F7F7F7) sobre --color-ink-primary (#171717) passa AAA (~15:1).
  • Fallback de canal: em SMS, primary colapsa em keyword ("RESPONDER PAGAR"); secondary/tertiary colapsam em texto; em voz, primary é a opção lida primeiro.
  • Estado loading: aria-label no botão descreve a ação em curso ("Carregando pagamento").

Do / Don't

Do

Label em verbo direto. Uma ação clara, sem ambiguidade.

Don't

Label em abstração. "Continuar", "Próximo", "OK" não informam o que vai acontecer.

Do

Tertiary para cancelar/voltar. A hierarquia de ênfase comunica a importância relativa das ações.

Don't

Três Teclas V-B na mesma tela — vira mancha. Primary é o acento, não o chão.

Componentes relacionados

  • Chip — quando a ação é filtro ou etiqueta.
  • Quick Actions Card — quando múltiplas ações rotineiras pedem agrupamento.

Markup de referência

HTML namespaced copiável — semente da "story" futura no Storybook. Para a variante primary, o CSS da Tecla V-B vive em sombra-e-elevacao.css e prototype/visual-reference/styles.css.

<button className="peppe-button peppe-button--secondary" type="button"> <span className="peppe-button__label">Ver depois</span> </button><button className="peppe-button peppe-button--tertiary" type="button"> <span className="peppe-button__label">Cancelar</span> </button><button className="peppe-button peppe-button--secondary" type="button" data-state="loading" aria-label="Carregando"> <svg className="peppe-button__spinner" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.5" strokeDasharray="42 14" strokeLinecap="round"/> </svg> <span className="peppe-button__label">Processar</span> </button><button className="peppe-tecla" type="button" aria-label="Pagar agora"> <span className="peppe-tecla__rim"> <span className="peppe-tecla__cap">Pagar agora</span> </span> </button> <!-- Variante compacta --> <button className="peppe-tecla peppe-tecla--sm" type="button" aria-label="Pagar"> <span className="peppe-tecla__rim"> <span className="peppe-tecla__cap">Pagar</span> </span> </button> /* CSS — componente-button.css */ .peppe-button {display: inline-flex; align-items: center; justify-content: center; gap: var(--space-8); padding: 0 var(--space-24); height: var(--touch-target-md); border: none; border-radius: var(--radius-button-md); font-family: var(--type-family-sans); font-size: var(--type-size-md); font-weight: var(--type-weight-medium); cursor: pointer;}/* Tecla V-B: CSS em sombra-e-elevacao.css → .peppe-tecla (socket — gradient + shadow direcionais) → .peppe-tecla__rim (borgonha — padding 4px shifta no pressed) → .peppe-tecla__cap (âmbar — anel bisel via border-box gradient) Estados: :hover, :active, :disabled (interativo) ou --hover, --pressed, --disabled (modifier pra demo estática). */