Tucano v0.37.2

Carregando

Spinner para a ação que a pessoa disparou e espera, como o botão de salvar; esqueleto para o conteúdo que ainda vai chegar e já tem forma conhecida, como a linha da tabela. O esqueleto evita o salto: o espaço já está reservado com o tamanho do que vem. Só classe, sem JavaScript.

Spinner

Clique em salvar: o botão fica ocupado por dois segundos.

Esqueleto

A forma do que vem, no lugar do que vem.

Exemplos

O spinner mede em em e pinta com currentColor, então acompanha o lugar onde está sem variante nenhuma.

Botão ocupado

aria-busy="true" com disabled. No botão, o spinner ocupa o lugar e o tamanho do ícone.

No texto

Na altura da letra, e na cor dela.

Buscando cobranças…

Linha de tabela

O esqueleto pode ser qualquer elemento, inclusive um <td>.

ClienteValor

Avatar e card

is-circle fica redondo na largura que você der.

Como usar

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

<span class="tuc-spinner is-lg"></span>

<div class="tuc-skeleton" style="width:60%"></div>
<span class="tuc-skeleton is-circle" style="width:36px"></span>

O esqueleto é um bloco de 1em de altura e da largura toda: a largura e, quando precisar, a altura são suas. Não escreva spinner à mão, com SVG ou borda própria — o toast de carregando e os componentes usam este.

Ocupado não é desativado

O disabled impede o segundo clique, mas o esmaecido de 50% diz "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.

Com o HTMX

htmx-indicator é a classe do próprio HTMX: escondida, e visível só durante a requisição. Junto do spinner, ele aparece e some sem uma linha de JavaScript.

<button class="tuc-btn is-primary" hx-post="{% url 'contract-save' contract.pk %}" hx-disabled-elt="this">
  <span class="tuc-spinner htmx-indicator"></span> Salvar
</button>

O esqueleto serve de conteúdo provisório para o que o HTMX vai buscar logo que a página abre. Quando a resposta chega, ela substitui o esqueleto no mesmo espaço, e nada pula.

<div hx-get="{% url 'customers-table' %}" hx-trigger="load" hx-swap="outerHTML">
  <span class="tuc-skeleton" style="width:60%"></span>
  <span class="tuc-skeleton" style="width:80%; margin-top:8px"></span>
</div>

Acessibilidade

O texto diz o que está acontecendo, e o spinner confirma. "Salvando" ao lado do spinner é anunciado; um spinner sozinho é um círculo girando para quem não vê.

O esqueleto é decoração: não seleciona texto, não recebe ponteiro e seu texto, se houver, fica transparente. Com prefers-reduced-motion o brilho do esqueleto para de vez, porque é só enfeite. O spinner continua girando, mais devagar: parado, ele deixaria de dizer "esperando" e viraria um círculo qualquer.

Classes

Classe ou atributoPara quê
.tuc-spinnerCírculo girando, de 1em, na cor do texto
is-lgNo spinner: 1.5em
.tuc-btn > .tuc-spinnerDentro do botão, no tamanho do ícone dele
aria-busy="true"No .tuc-btn: ocupado, com cor cheia e cursor de espera, mesmo com disabled
.tuc-skeletonBloco com brilho, no lugar do conteúdo que vem
is-circleNo esqueleto: redondo, com a altura igual à largura
htmx-indicatorDo HTMX: mostra o elemento só durante a requisição