Ir al contenido

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
Svelte
<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
Svelte
<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.

Svelte
<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
Svelte
<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

Props de Spinner
PropDescripció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 falseOculta 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 con live). Así se anuncia aunque el producto lo monte con {#if}.
  • El aro es decorativo (aria-hidden); lo que se lee es label. Con hideLabel el 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 loading de Button, que conserva su texto, un Spinner con hideLabel puede 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-muted por defecto). Si lo cambias, usa un rol de texto: el aro tiene que verse contra el fondo. En colores forzados, el aro es CanvasText y 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. loading de 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.