Tucano v0.37.2

Botão

Nasceu do que os componentes precisavam por dentro — o "Desfazer" do toast, o "Aplicar" do calendário. Em vez de cada um inventar o seu, sai tudo daqui, e fica disponível para o seu projeto. É só classe: um <button> continua sendo um <button>.

Exemplos

Variante, tamanho e estado são classes e atributos que se combinam.

Tamanhos

is-sm tem 30px, o padrão sai de --tuc-control-height e is-lg tem 44px.

Com ícone

O <svg> ganha o tamanho do botão sozinho. is-icon deixa quadrado — e aí o aria-label é obrigatório.

Ocupado

aria-busy="true" com .tuc-spinner. Clique em "Salvar" para ver a troca.

Desativado

disabled não recebe clique nem foco; aria-disabled="true" segue focável e anunciado.

Largura toda

is-block ocupa a linha — o botão de um formulário estreito ou de um celular.

Como link

Num <a> a classe tira o sublinhado; é o certo quando o botão navega, e não age.

Como usar

tuc-btn e uma variante. Sem variante o botão fica transparente, sem borda — a base de que as variantes partem.

<button type="submit" class="tuc-btn is-primary">Salvar</button>
<button type="button" class="tuc-btn is-outline is-sm">Cancelar</button>
<button type="button" class="tuc-btn is-ghost is-icon" aria-label="Fechar">
  <svg>...</svg>
</button>
<a class="tuc-btn is-link" href="/help/">Saiba mais</a>

No formulário do Django

O botão é do template, não do form. Com type="submit" ele envia o formulário como sempre.

<form method="post">
  {% csrf_token %}
  {{ form }}
  <a class="tuc-btn is-outline" href="{% url 'customers' %}">Cancelar</a>
  <button type="submit" class="tuc-btn is-primary">Salvar</button>
</form>

Em JavaScript

Não há componente para instanciar. O que se faz em código é trocar o estado — por exemplo, ocupado durante um envio:

const btn = document.querySelector('#save');
btn.setAttribute('aria-busy', 'true');
btn.disabled = true;               // impede o segundo clique
btn.prepend(Object.assign(document.createElement('span'), { className: 'tuc-spinner' }));

// ...quando terminar
btn.removeAttribute('aria-busy');
btn.disabled = false;
btn.querySelector('.tuc-spinner').remove();

Variantes e quando usar

Uma ação principal por área. As outras recuam em peso visual, e a destrutiva se distingue pela cor.

ClassePara quê
is-primaryAção principal, na cor de destaque (--tuc-accent)
is-outlineAção secundária, com borda
is-ghostTerciária, sem peso visual — ações dentro de tabela, barra de ferramentas
is-dangerDestrutiva, pintada com --tuc-danger-fill
is-linkParece link, se comporta como botão

Por que o vermelho do botão é outro token

--tuc-danger é mais claro no tema escuro, para ter contraste como texto — e um botão pintado com ele ficaria pastel com texto branco. --tuc-danger-fill é o mesmo nos dois temas.

Botão e campo têm a mesma altura

Os dois saem de --tuc-control-height — 38px, ou 44px no layout compacto, onde o alvo de toque precisa ser maior. Raio e borda vêm de --tuc-radius-md e --tuc-border-width. Um botão ao lado de um select fica alinhado sem ajuste.

Ocupado e desativado

Os dois impedem a ação, mas dizem coisas diferentes, e por isso têm desenhos diferentes.

<button class="tuc-btn is-primary" aria-busy="true" disabled>
  <span class="tuc-spinner"></span> Salvando
</button>

<button class="tuc-btn is-outline" aria-disabled="true">Exportar</button>

Ocupado não é desativado

O disabled junto do aria-busy impede o segundo clique, mas o esmaecido de 50% diria "não disponível" — e o botão está trabalhando. Com aria-busy="true" ele fica com a cor cheia e o cursor de espera. O spinner mede em em e pinta com currentColor: dentro do botão ele ocupa o lugar do ícone e sai branco num primário, sem variante.

Desativado mostra o cursor de bloqueio

Nada de pointer-events: none: sem receber o ponteiro o elemento não troca o cursor, e a pessoa fica sem sinal de que o botão não responde. Num <button disabled> o navegador já impede o clique. Com aria-disabled="true" o clique continua chegando de propósito — é o botão que segue focável e anunciado, e quem usa o atributo trata o clique no próprio manipulador.

Desativado também não reage ao hover — mudar de cor sugeriria que ainda funciona — e perde a sombra. Ao pressionar, o botão encolhe de leve: num toque, sem hover, a cor sozinha não confirma que o dedo acertou o alvo. Com prefers-reduced-motion esse movimento sai.

Teclado e acessibilidade

É o <button> do navegador: foco, Enter e Espaço vêm de graça. O que cabe ao template é escolher o elemento certo e dar nome ao que não tem texto.

TeclaAção
TabChega no botão, com o anel de foco dos campos; pula o disabled, não o aria-disabled
Enter EspaçoAciona o <button>; num <a class="tuc-btn">, só o Enter

Classes

Só CSS, sem JavaScript. Não escreva um segundo desenho de botão: ação dentro de tabela ou de bloco de código também é .tuc-btn, com classe própria só para posicionar.

Classe ou atributoPara quê
tuc-btnA base: altura, fonte, raio, foco. Vale em <button> e <a>
is-primary is-outline is-ghost is-danger is-linkVariante
is-sm is-lgTamanho: 30px e 44px; o ícone acompanha
is-iconQuadrado, só ícone; combina com is-sm e is-lg
is-blockOcupa a largura toda
disabledEsmaecido, cursor de bloqueio, sem hover; o navegador barra o clique
aria-disabled="true"Mesmo desenho, mas focável e com o clique chegando
aria-busy="true"Ocupado: cor cheia e cursor de espera, mesmo com disabled
.tuc-spinner dentroOcupa o lugar e o tamanho do ícone
--tuc-btn-iconTamanho do <svg> filho; cada tamanho de botão define o seu