Componentes · Ola 3 · Estados
Spinner
Dice que algo está cargando, con un aro que gira y un texto para el lector de pantalla. Es el mismo aro que el loading de Button: 1,5
px de currentColor con un hueco.
import { Spinner } from '@archeblack/ui';
Ejemplos
Con texto
El texto dice qué está cargando y se ve al lado del aro.
Cargando proyectos
<script lang="ts">
import { Spinner } from '@archeblack/ui';
</script>
<Spinner label="Cargando proyectos" /> Tallas
sm, md y lg, con hideLabel: el texto queda solo para el lector de pantalla.
Cargando Cargando Cargando
<script lang="ts">
import { Spinner } from '@archeblack/ui';
</script>
<!-- Con hideLabel el texto no se ve, pero el lector de pantalla lo lee. -->
<div style="display: flex; align-items: center; gap: var(--arche-spacing-6)">
<Spinner size="sm" label="Cargando" hideLabel />
<Spinner size="md" label="Cargando" hideLabel />
<Spinner size="lg" label="Cargando" hideLabel />
</div> Mientras carga
Se monta al empezar y se quita al terminar; el lector anuncia el texto al aparecer.
<script lang="ts">
import { Button, Spinner } from '@archeblack/ui';
let state = $state<'idle' | 'loading' | 'done'>('idle');
function load() {
if (state === 'loading') return;
state = 'loading';
setTimeout(() => (state = 'done'), 2000);
}
</script>
<div style="display: grid; justify-items: start; gap: var(--arche-spacing-4)">
<Button variant="secondary" onclick={load}>Cargar registros</Button>
<!--
Aunque se monte con {#if}, el Spinner pinta primero la región status vacía y el texto llega
dos cuadros después: el lector de pantalla lo anuncia.
-->
{#if state === 'loading'}
<Spinner label="Cargando registros" />
{:else if state === 'done'}
<p>Sin errores en la última hora.</p>
{/if}
</div> Color
El aro toma el color del texto: text-muted por defecto, o el rol que le pongas.
Sincronizando Publicando Verificando el dominio
<script lang="ts">
import { Spinner } from '@archeblack/ui';
</script>
<!-- El aro es currentColor: toma el color del texto del Spinner. -->
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: var(--arche-spacing-6)">
<Spinner label="Sincronizando" />
<Spinner label="Publicando" style="color: var(--arche-color-text-strong)" />
<Spinner label="Verificando el dominio" style="color: var(--arche-color-link)" />
</div> Props
| Prop | Descripción |
|---|---|
label? string Por defecto 'Cargando' | Qué está cargando, en una frase corta («Cargando proyectos»). Es el texto de la región status. |
hideLabel? boolean Por defecto false | Oculta el texto a la vista; el lector de pantalla lo sigue leyendo. |
size? 'sm' | 'md' | 'lg' Por defecto 'md' | Aro de 12, 14 o 18 px dentro de la caja de un Icon de la misma talla (16, 20 o 24 px): reemplaza a un ícono sin mover el texto. |
class? ClassValue | Clases del producto; se suman a arche-spinner. |
...rest HTMLAttributes<HTMLSpanElement> | Van a la raíz (<span role="status">): id, style (el color pinta el aro y el texto) y data-*. |
Accesibilidad
- La raíz es un
role="status": el texto se anuncia al aparecer, sin interrumpir. Se monta vacía y el texto llega dos cuadros después, porque NVDA y JAWS solo anuncian los cambios de una región que ya estaba en la página (lo mismo que Alert conlive). Así se anuncia aunque el producto lo monte con{#if}. - El aro es decorativo (
aria-hidden); lo que se lee eslabel. ConhideLabelel texto sigue en la región, fuera de la vista. - Movimiento reducido: el aro gira tres veces más lento (2,4 s por vuelta) en lugar de detenerse. A diferencia del
loadingde Button, que conserva su texto, un Spinner conhideLabelpuede ser lo único que dice que algo está en curso: quieto parecería un ícono roto. Un giro lento y chico no desplaza nada en la pantalla. - El color sale del texto (
text-mutedpor defecto). Si lo cambias, usa un rol de texto: el aro tiene que verse contra el fondo. En colores forzados, el aro esCanvasTexty conserva su hueco. - Cuando termina de cargar, quita el Spinner y muestra el contenido, o un Empty state si no hay nada. Si el área que carga es grande, márcala además con
aria-busy="true"(ver Skeleton).
Qué evitar
- Un Spinner dentro de un botón.
loadingde Button, que dibuja el mismo aro y cancela el clic. - Un Spinner que reemplaza una página o una lista entera mientras carga. Un Skeleton con la forma del contenido: la página no salta al llegar.
- Un Spinner para una tarea de la que se sabe cuánto falta. Un Progress determinado.
- Varios Spinner a la vez, uno por cada pieza de la misma vista. Uno solo para lo que carga junto, con un texto que diga qué es.