Makuco UI
ComponentesFeedback

Spinner

Indicador de carregamento inline com `mk-spinner` — um ícone em rotação contínua, com tamanho, cor e desenho configuráveis.

O mk-spinner sinaliza que uma operação está em andamento, no fluxo do documento: é um mk-icon em rotação contínua. Não gerencia estado, não emite eventos e não é focável — quem monta e desmonta o indicador é o consumidor, por renderização condicional.

É a única definição de velocidade de rotação do sistema, exposta como --mk-spinner-duration (1s). mk-button, mk-autocomplete, mk-mentions e mk-search consomem mk-spinner internamente, então ajustar essa propriedade alcança os quatro.

Quando usar

Use quando:
  • O carregamento é escopado a um botão, uma célula de tabela, um card ou uma região da tela.

  • O resto da interface continua utilizável durante a operação.
  • A duração é desconhecida e não há percentual a exibir.
Prefira uma alternativa quando:
  • A operação afeta a página inteira e a interação concorrente causaria problema — use o Loading.

  • O progresso é conhecido e mensurável — use a Progress Bar ou o Meter.
  • O layout da área carregando é previsível — use o Skeleton.

Padrão

size="md", color="inherit" e icon="loader-circle", girando uma volta por segundo com easing linear.

import { MkSpinner } from '@db1/makuco-ui-react';

<MkSpinner />
<mk-spinner></mk-spinner>

Tamanhos

size usa a mesma escala semântica do Icon: xs (--db1-spacing-3), sm (--db1-spacing-4), md (--db1-spacing-6), lg (--db1-spacing-8), xl (--db1-spacing-9) e xxl (--db1-spacing-12).

import { MkSpinner } from '@db1/makuco-ui-react';

<MkSpinner size="xs" />
<MkSpinner size="sm" />
<MkSpinner size="md" />
<MkSpinner size="lg" />
<MkSpinner size="xl" />
<MkSpinner size="xxl" />
<mk-spinner size="xs"></mk-spinner>
<mk-spinner size="sm"></mk-spinner>
<mk-spinner size="md"></mk-spinner>
<mk-spinner size="lg"></mk-spinner>
<mk-spinner size="xl"></mk-spinner>
<mk-spinner size="xxl"></mk-spinner>

Cores

Os cinco valores semânticos — brand, success, error, warning e info — definem --mk-icon-color a partir dos tokens --icon-*, a mesma camada que colore o Icon.

inherit é o padrão e não define cor alguma: o ícone interno resolve pela cascata e cai em --icon-high-emphasis quando nada no contexto declara --mk-icon-color.

import { MkSpinner } from '@db1/makuco-ui-react';

<MkSpinner color="brand" />
<MkSpinner color="success" />
<MkSpinner color="error" />
<MkSpinner color="warning" />
<MkSpinner color="info" />
<MkSpinner color="inherit" />
<mk-spinner color="brand"></mk-spinner>
<mk-spinner color="success"></mk-spinner>
<mk-spinner color="error"></mk-spinner>
<mk-spinner color="warning"></mk-spinner>
<mk-spinner color="info"></mk-spinner>
<mk-spinner color="inherit"></mk-spinner>

Cor herdada

Propriedades customizadas atravessam fronteiras de shadow DOM. Com color="inherit", um --mk-icon-color declarado por qualquer ancestral alcança o ícone dentro do spinner — é assim que o indicador do Button já sai na cor do botão. Abaixo, spinner e ícone recebem a mesma cor do container.

import { MkIcon, MkSpinner } from '@db1/makuco-ui-react';

<div style={{ '--mk-icon-color': 'var(--icon-success)' }}>
  <MkSpinner />
  <MkIcon name="check" size="md" />
</div>
<div style="--mk-icon-color: var(--icon-success)">
  <mk-spinner></mk-spinner>
  <mk-icon name="check" size="md"></mk-icon>
</div>

Um --mk-icon-color declarado no próprio elemento mk-spinner vence a prop color, porque declarações da árvore externa prevalecem sobre declarações de :host na árvore interna. Por isso color="brand" não tem efeito visível dentro de um contexto que declara a propriedade diretamente na tag:

/* Vence `color="brand"`: a declaração alcança o próprio host. */
.mk-search__spinner {
  --mk-icon-color: var(--stroke-brand);
}

/* Perde para `color="brand"`: o valor chega por herança, e a regra
   `:host([color="brand"])` declara no elemento. */
.meu-painel {
  --mk-icon-color: var(--icon-info);
}

Para colorir pela prop nesse cenário, remova a declaração que alcança a tag.

Ícone customizado

icon aceita qualquer nome do catálogo de ícones e troca o desenho girado. O padrão é loader-circle.

import { MkSpinner } from '@db1/makuco-ui-react';

<MkSpinner icon="refresh-cw" color="brand" />
<mk-spinner icon="refresh-cw" color="brand"></mk-spinner>

Slot de ícone

O slot icon substitui o indicador padrão e gira junto, porque a animação vive no wrapper interno e não no conteúdo. O ícone interno existe apenas enquanto nada está atribuído ao slot: preenchido o slot, a prop icon é ignorada.

import { MkIcon, MkSpinner } from '@db1/makuco-ui-react';

<MkSpinner size="xl">
  <MkIcon slot="icon" name="loader" size="xl" />
</MkSpinner>
<mk-spinner size="xl">
  <mk-icon slot="icon" name="loader" size="xl"></mk-icon>
</mk-spinner>

Modo anunciante

Sem label, o host recebe aria-hidden="true" e é invisível para tecnologia assistiva. Com label, recebe role="status" e aria-live="polite", e o texto é renderizado visualmente oculto. label="" se comporta como ausente.

import { MkSpinner } from '@db1/makuco-ui-react';

<MkSpinner label="Carregando resultados" color="brand" />
<mk-spinner label="Carregando resultados" color="brand"></mk-spinner>

Inline com texto

O host é display: inline-flex e alinha ao centro do texto ao lado. size="sm" acompanha corpos de texto correntes.

import { MkSpinner } from '@db1/makuco-ui-react';

<span style={{ display: 'inline-flex', alignItems: 'center', gap: '8px' }}>
  <MkSpinner size="sm" />
  Carregando dados
</span>
<span style="display: inline-flex; align-items: center; gap: 8px">
  <mk-spinner size="sm"></mk-spinner>
  Carregando dados
</span>

Duração da rotação

--mk-spinner-duration define a duração de uma volta completa e vale 1s por padrão. Não há prop de duração: a velocidade é ajustada por essa propriedade, mantendo uma definição única no sistema.

import { MkSpinner } from '@db1/makuco-ui-react';

<MkSpinner style={{ '--mk-spinner-duration': '2.5s' }} />
<mk-spinner style="--mk-spinner-duration: 2.5s"></mk-spinner>

Spinner ou Loading

ComponenteAlcanceQuando usar
mk-spinnerInline, no fluxo do documento.

O carregamento é escopado a um controle ou a uma região, e o resto da interface continua utilizável.

mk-loadingOverlay de tela cheia, acionado por showLoading().

A operação afeta a página inteira: o overlay pinta um backdrop, aplica inert nos irmãos de body e trava o scroll enquanto está aberto.

Props — mk-spinner

PropTipoPadrãoDescrição
size"xs" | "sm" | "md" | "lg" | "xl" | "xxl""md"Diâmetro do indicador, na mesma escala semântica do Icon. Refletido como atributo.
color"brand" | "success" | "error" | "warning" | "info" | "inherit""inherit"

Cor do traço. inherit não define cor: defere ao --mk-icon-color do contexto. Refletido como atributo.

iconIconName"loader-circle"Ícone girado. Ignorado quando o slot icon está preenchido.
labelstring

Nome acessível. Quando fornecido, o host recebe role="status" e aria-live="polite" e o texto é renderizado visualmente oculto. Quando ausente ou vazio, o host recebe aria-hidden="true".

CSS custom properties

PropriedadePadrãoDescrição
--mk-spinner-duration1sDuração de uma volta completa do indicador.
--mk-icon-color

Não é definida quando color="inherit", e é consumida pelo ícone interno. Declarada na própria tag, vence a prop color.

Eventos

Não emite eventos. Não há interação para reportar e o componente não conhece o ciclo de vida da operação que representa.

Slots

ComponenteSlotDescrição
mk-spinnericon

Substitui o indicador padrão e gira junto. Aceita um mk-icon, um svg ou um img. Quando preenchido, a prop icon é ignorada.

Acessibilidade

  • Sem label, o host recebe aria-hidden="true" e não tem role. É o padrão porque o uso mais comum é dentro de outro componente que já comunica o próprio estado — no Button, o botão já expõe nome e estado, e um role="status" no spinner produziria anúncio duplicado.
  • Com label, o host recebe role="status" e aria-live="polite". O anúncio aguarda uma pausa na fala em vez de interromper.
  • O texto de label é renderizado como conteúdo visualmente oculto em vez de aplicado como aria-label, permanecendo disponível a ferramentas que leem conteúdo em vez de atributos.
  • label="" é tratado como ausente: um role="status" com nome acessível vazio é pior que não ter role.
  • O svg dentro do Icon já carrega aria-hidden="true", então o desenho nunca é anunciado em nenhum dos dois modos.
  • O conteúdo não muda enquanto o spinner vive, então a live region não reanuncia a cada volta da animação.
  • O indicador é um elemento gráfico não textual e se enquadra no critério 1.4.11 (Non-text Contrast), com 3:1 contra o fundo adjacente. Os cinco valores semânticos herdam de --icon-*, já validados como cor de ícone nos dois temas.
  • A rotação permanece ativa sob prefers-reduced-motion: reduce. O loader-circle congelado em rotate(0) é um arco incompleto, lido como artefato de renderização, e a WCAG 2.2.2 (Pause, Stop, Hide) se aplica a movimento não essencial. O mesmo precedente vale no Loading.
TeclaComportamento
TabO foco passa por cima — o spinner não entra na ordem de tabulação.

On this page