## 2.1 Botão

| Variante | Visual | Uso | Quantos por contexto |
|---|---|---|---|
| `primary` | fundo `primary`, texto `primary-foreground` | a ação principal do contexto | **1** |
| `secondary` | fundo `secondary` | ação de apoio preenchida | vários |
| `outline` | borda `border` e fundo `background` (no escuro, borda `input` e fundo `input` a 30%) | ação de apoio, filtros, "Editar" | vários |
| `ghost` | sem fundo nem borda; `muted` no hover | cancelar, voltar, botão só de ícone em barra | com moderação |
| `link` | texto no token `link` (a primária; no escuro, mais clara, 1.2), sublinhado no hover | navegação dentro de texto | com moderação |
| `danger` | tinta de `danger` (10%; 20% no escuro) com o texto em `danger-strong` | só ação destrutiva, só depois de confirmação ou dentro dela | 1 |

- Tamanhos, os do shadcn: `xs` 24px, `sm` 28px, padrão 32px, `lg` 36px. **Não existe `xl`.** Só de
  ícone: quadrado na mesma altura (`icon-xs`, `icon-sm`, `icon`, `icon-lg`). **Padrão em tudo,
  inclusive no "Novo…"**: botões, campos e filtros de uma mesma barra têm a mesma altura. `sm` e `xs`
  só dentro de outro componente. `lg` não se usa nas telas dos sistemas.
- Ícone à **esquerda** do rótulo, 16px (14 no `sm`, 12 no `xs`), a 6px do texto (4 no `sm` e no
  `xs`). Ícone à direita só para "abre algo" (seta, chevron, link externo).
- O `danger` é a tinta do `destructive` do shadcn com o texto no tom `-strong`: com o texto em
  `danger` puro, o escuro fica abaixo de 4,5:1 (1.2).
- **Rótulo é verbo no infinitivo:** "Salvar", "Excluir fila", "Nova fila". Nunca "OK", "Sim",
  "Clique aqui".
- **Botão só de ícone:** `aria-label` **e** tooltip com o mesmo texto. Sem exceção.
- **Carregando:** desabilitado, com o Spinner no lugar do ícone e o rótulo mantido ("Salvar", não
  "Salvando…").
- Desabilitado: 50% de opacidade, sem hover, cursor padrão. Desabilitado não some: fica visível
  com tooltip explicando por quê, quando o motivo não é óbvio.
- Link com cara de botão é um link com o estilo do botão. Nunca um link dentro de um botão.
- **"Novo…" (criar) fica dentro do card da lista que ele alimenta, no canto superior direito**
  *(decisão do usuário, 2026-10-26)*: `primary`, no `size` padrão do `Button` (sem a prop `size`, 32px), da mesma altura da busca,
  dos filtros e dos outros botões da barra *(o usuário reviu a D5: em `lg`, ficava desalinhado deles)*;
  ícone `plus`, o único primário do card. Card com título: nas ações do cabeçalho (`CardAction`). Card sem
  título: no fim da primeira linha da barra de ferramentas, depois da busca e dos filtros (3.5).
  Abaixo de 40rem de largura do card, vira botão só de ícone (`icon`) com `aria-label` e tooltip
  ("Nova fila"). Nunca no header nem numa barra acima do card (3.3).
- Não existe botão "Atualizar": os dados se atualizam sozinhos (3.8). "Tentar de novo" continua
  nos estados de erro.

### Código (shadcn-tailwind) · Botão

```tsx
import { Plus } from "lucide-react";
import { Button, buttonVariants } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";

// tamanhos do shadcn: xs 24 · sm 28 · default 32 · lg 36 (não existe xl); nunca h-*/px-* por className
// "Novo…": no canto superior direito do card que ele alimenta, o único default (= primary) do card,
// no tamanho padrão: a mesma altura da busca, dos filtros e dos outros botões da barra (nada de lg).
// Abaixo de 40rem de card vira só ícone, com aria-label e tooltip. Não existe botão "Atualizar" (3.8).
// components/botao-novo.tsx; o Card (ou o contêiner da tabela) leva className="@container/card"
export function BotaoNovo({ rotulo, onClick }: { rotulo: string; onClick: () => void }) {
  return (
    <>
      <Button className="hidden @min-[40rem]/card:inline-flex" onClick={onClick}><Plus data-icon="inline-start" />{rotulo}</Button>
      <Tooltip>
        <TooltipTrigger render={<Button size="icon" aria-label={rotulo} className="@min-[40rem]/card:hidden" onClick={onClick} />}><Plus /></TooltipTrigger>
        <TooltipContent>{rotulo}</TooltipContent>
      </Tooltip>
    </>
  );
}

// salvando: desabilitado, Spinner no lugar do ícone, rótulo mantido
<Button type="submit" disabled={isPending}>
  {isPending && <Spinner data-icon="inline-start" />}
  Salvar
</Button>

// link com cara de botão: nunca <Link> dentro de <Button>
<Link href="/contatos" className={buttonVariants({ variant: "outline" })}>Contatos</Link>
```

---
Exemplo vivo: https://design.ideiabusiness.com.br#botoes · Relacionados: patterns/barra-de-acoes, components/card · Fonte: guide/components/botao.md
