Uranus® Design System

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 um aria-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>
  );
}
VarianteQuando usar
primaryPadrão. A ação mais proeminente de uma superfície.
secondaryAções de apoio que ainda merecem ênfase.
outlineAlternativas de menor ênfase, geralmente pareadas com primary.
ghostToolbar, ícones inline, afordances terciárias.
destructiveAções irreversíveis ou de alta consequência.
linkNavegaçã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>
  );
}

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 primary por 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 primary lado a lado.
  • Não use destructive para ações reversíveis.
  • Não remova o anel de foco (focus-visible:ring).

Acessibilidade

  • Teclado: Enter e Espaço ativam 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 um aria-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.