Lo que le dice al usuario qué pasó, qué está pasando y qué falta por cargar.
Tres componentes que no necesitan librería: un div con rol ARIA, un rectángulo que parpadea y un círculo con una letra. Todo el color sale de tokens y está medido en los dos temas (lib/theme-contrast.test.ts).
El tono lo identifica el canto de 4 px, no el relleno. Y no es gusto: ningún escalón de relleno llega al piso de 1.2:1 en los dos temas para los cinco tonos — el -50 que usa el de Subframe mide 1.02–1.09 en claro, o sea que la caja prácticamente no existe. El canto en -700 mide 4.71:1 en el peor caso. Míralo en oscuro: la barra cambia de dirección con el tema, la caja no.
brand-800 sobre brand-100.neutral-800 sobre neutral-100.error-800 sobre error-100.warning-800 sobre warning-100.success-800 sobre success-100.info-800 sobre info-100.Los tres tonos de estado llevan tres dibujos distintos, y el informativo un cuarto. El Alert de Subframe pone el mismo icono en las cinco variantes, así que un error y un éxito solo se diferencian por el color — lo que prohíbe WCAG 2.2 SC 1.4.1. Entrecierra los ojos hasta perder el color: aquí se siguen distinguiendo.
El icono se alinea con la primera línea del título, no con el centro de la caja: en un aviso de tres renglones, centrado, se ve flotando. Las acciones no se encogen; el cuerpo es quien cede el ancho.
Por defecto un aviso no es una región live, y ese defecto es la decisión más cara del componente: los 20 avisos del portal son banners de estado de pantalla, y ponerles role="alert" sería una interrupción asertiva en cada carga de cada pantalla. MDN lo dice literal: el rol alert es para contenido que aparece, no para el que ya está al cargar. Pulsa el botón: ese aviso sí aparece, y por eso lleva live.
La barra es neutral-300, no el neutral-200 de Subframe: contra la página en tema claro el -200 mide 1.1341, bajo el piso de 1.2 — y la página es justo donde más esqueletos hay. Además son aria-hidden siempre, y el parpadeo va tras motion-safe:, así que quien pidió menos movimiento no lo ve.
Un esqueleto no es una barra suelta: es la forma de lo que va a llegar. Los anchos son irregulares y deterministas (indexados, nunca aleatorios) para que el servidor y el navegador pinten lo mismo y no haya error de hidratación.
🔴 Y hasta el 2026-08-20 esta misma vitrina no lo cumplía. Los tres anchos iban por className, y SkeletonText emitía w-full: las dos son la misma propiedad y gana el orden de la hoja, así que las tres filas salían idénticas debajo de un texto que prometía lo contrario. Ahora el ancho va por width, que es style y no puede perder.
SkeletonText llega a 40 px y SkeletonCircle a 36. Una gráfica de 320 px, un visor de 560 o un avatar de 64 no caben en ninguna escala — medido sobre los 42 esqueletos de una app real, ~20 se salen. height es obligatorio: un esqueleto que reserva menos de lo que llega hace saltar la página al cargar, y con valor por omisión ese fallo se escribe solo. Va por style, como el SkeletonBox de Primer y el Skeleton de MUI.
Tinta -800 uniforme sobre relleno -100. La inicial es texto, así que debe 4.5:1 y no 3:1; con el -700 que usa el Badge, el ámbar se queda en 4.5097 — a una centésima del suelo. Una regla con margen antes que cinco excepciones al límite.
El tipo no deja escribir un avatar que no lo haya decidido: name (lo anuncia) o decorative (desaparece del árbol). Los dos de abajo se ven idénticos y suenan distinto — que es exactamente por lo que esto no podía quedarse en una convención. Junto a un nombre en texto lo correcto es decorative, o el lector dice «J, Jane Doe».
La foto se pinta encima de las iniciales, nunca en su lugar. Si da 404 —el broker apuntando a una cuenta que no existe, que pasó— la letra simplemente se queda: ni imagen rota, ni círculo vacío, ni salto de maquetación. Y la inicial se corta por punto de código: con charAt(0) un nombre que empieza por un carácter fuera del BMP devuelve medio par suplente.
🔴 El tono es color, y el color no puede ser el único medio (SC 1.4.1). Por eso title es obligatorio y la teja del icono va decorativa: si la teja tuviera nombre accesible, la severidad viviría en un aria-label y el título podría quedarse genérico. Compara los tres de abajo con el color apagado — los tres siguen diciendo qué pasa.
No perteneces a ninguna empresa
Pide a tu administrador que te dé acceso.
Ninguna empresa coincide
Prueba con menos letras.
No pudimos verificar tu acceso
El tercero va sin icono a propósito: sin él no se dibuja una teja vacía — un círculo tintado sin nada dentro lee como un adorno roto, y en error como una alarma sin causa.