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.
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
| Componente | Alcance | Quando usar |
|---|---|---|
mk-spinner | Inline, no fluxo do documento. | O carregamento é escopado a um controle ou a uma região, e o resto da interface continua utilizável. |
mk-loading | Overlay de tela cheia, acionado por showLoading(). | A operação afeta a página inteira: o overlay pinta um backdrop, aplica |
Props — mk-spinner
| Prop | Tipo | Padrão | Descriçã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. |
icon | IconName | "loader-circle" | Ícone girado. Ignorado quando o slot icon está preenchido. |
label | string | — | Nome acessível. Quando fornecido, o host recebe |
CSS custom properties
| Propriedade | Padrão | Descrição |
|---|---|---|
--mk-spinner-duration | 1s | Duração de uma volta completa do indicador. |
--mk-icon-color | — | Não é definida quando |
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
| Componente | Slot | Descrição |
|---|---|---|
mk-spinner | icon | Substitui o indicador padrão e gira junto. Aceita um |
Acessibilidade
- Sem
label, o host recebearia-hidden="true"e não temrole. É 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 umrole="status"no spinner produziria anúncio duplicado. - Com
label, o host receberole="status"earia-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 comoaria-label, permanecendo disponível a ferramentas que leem conteúdo em vez de atributos. label=""é tratado como ausente: umrole="status"com nome acessível vazio é pior que não terrole.- O
svgdentro do Icon já carregaaria-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. Oloader-circlecongelado emrotate(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.
| Tecla | Comportamento |
|---|---|
Tab | O foco passa por cima — o spinner não entra na ordem de tabulação. |