Button
Dispara uma ação. O elemento interativo mais comum da interface.
Button é a forma canônica de disparar uma ação. Para navegação, prefira colocar um <a> (ou <Link />) dentro de um <Button asChild> ao invés de ligar onClick a um router.push.
import { Button } from '@uranus-workspace/design-system';
export default function ButtonDefault() {
return <Button>Novo projeto</Button>;
}
Anatomia
- Rótulo — a única parte obrigatória. Sempre legível por humanos.
- Ícone (leading ou trailing) — opcional. Mantenha-o pequeno e nunca substitua o rótulo por um ícone sem usar
size="icon"combinado a umaria-label.
Variantes
import { Button } from '@uranus-workspace/design-system';
export default function ButtonVariants() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button variant="destructive">Destructive</Button>
</div>
);
}
| Variante | Quando usar |
|---|---|
primary | Padrão. A ação mais proeminente de uma superfície. |
secondary | Ações de apoio que ainda merecem ênfase. |
outline | Alternativas de menor ênfase, geralmente pareadas com primary. |
ghost | Toolbar, ícones inline, afordances terciárias. |
destructive | Ações irreversíveis ou de alta consequência. |
link | Navegação inline que se lê como texto corrido. |
Tamanhos
Os tamanhos disponíveis são sm, md (padrão), lg e icon (quadrado, para botões apenas de ícone com nome acessível).
import { Button } from '@uranus-workspace/design-system';
export default function ButtonSizes() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
);
}
Com ícone
Ícones do Lucide ficam automaticamente dimensionados em size-4 graças ao seletor [&_svg] nas variantes. Não precisa aplicar classes no ícone.
import { Button } from '@uranus-workspace/design-system';
import { Plus } from 'lucide-react';
export default function ButtonWithIcon() {
return (
<Button>
<Plus />
Novo projeto
</Button>
);
}
Estado de carregamento
Combine disabled com um Spinner para indicar que uma ação assíncrona está em andamento. Mantenha o rótulo — trocar por "Carregando…" confunde leitores de tela.
import { Button, Spinner } from '@uranus-workspace/design-system';
export default function ButtonLoading() {
return (
<Button disabled>
<Spinner />
Salvando…
</Button>
);
}
Como link
Use asChild para renderizar o filho imediato com as classes e o comportamento do botão. Essa é a forma correta de fazer um botão navegar:
import Link from 'next/link';
import { Button } from '@uranus-workspace/design-system';
<Button asChild>
<Link href="/projetos">Ir para projetos</Link>
</Button>Faça
- Use apenas um botão
primarypor tela — ele é a âncora visual da tarefa principal. - Coloque ações destrutivas dentro de um diálogo de confirmação, nunca soltas na superfície.
- Mantenha rótulos no imperativo: "Criar projeto", não "Criação".
Não faça
- Não empilhe dois botões
primarylado a lado. - Não use
destructivepara ações reversíveis. - Não remova o anel de foco (
focus-visible:ring).
Acessibilidade
- Teclado:
EntereEspaçoativam o botão. - Botões desabilitados são anunciados como tal por tecnologias assistivas. Prefira ocultar em vez de desabilitar quando a ação não fizer sentido naquele contexto.
- Botões apenas de ícone (
size="icon") precisam obrigatoriamente de umaria-label.
API
Consulte as definições TypeScript geradas em @uranus-workspace/design-system. ButtonProps estende ButtonHTMLAttributes<HTMLButtonElement>, então todos os atributos nativos de botão funcionam.