Calidad, medida
Lo que esta página afirma está comprobado y se puede repetir: cada cifra dice de cuándo es y con qué se midió, y lo que no se ha medido se dice tal cual.
Accesibilidad
La biblioteca no declara un nivel de conformidad: eso lo firma una auditoría externa sobre una aplicación concreta, y no existe todavía. Lo que sí es público es lo que se pasa en cada cambio:
| Qué | Cómo |
|---|---|
| Las reglas de WCAG 2.0, 2.1 y 2.2 AA que axe sabe medir | axe-core con Playwright sobre la historia interactiva de cada ficha y las páginas de repaso, en claro, en oscuro y en móvil. En la CI bloquea la fusión con el tema claro; oscuro y móvil se pasan antes de subir. |
| El contraste de los tokens de color | Cada par de texto y fondo, en los dos temas, en cada ejecución de las pruebas. |
| Teclado, foco y movimiento | Pruebas en un navegador de verdad: el aro de foco, el foco que vuelve al cerrar una capa, el arrastre con teclado, prefers-reduced-motion y la impresión. |
| Objetivos táctiles | Geometría medida en el navegador. |
En tres motores
Las pruebas de comportamiento (foco, capas, teclado, arrastre, impresión, movimiento) corren en Chromium, y también en Firefox y WebKit: ahí salieron dos fallos que Chromium no veía —el foco que Safari perdía al cerrar un desplegable y los diálogos que desaparecían de golpe en Firefox y Safari—. La CI lleva una puerta rápida con los dos.
Peso
Medido el 19 de octubre de 2026 con el benchmark del repositorio de la biblioteca: el mismo empaquetador (Vite, en producción) y los mismos ajustes para todas, con React fuera de la cuenta. Es lo que pesa en el bundle, comprimido con gzip, lo que se pide y se usa:
| Qué se pide | @amset/ui | react-aria-components | shadcn/ui | HeroUI | antd | MUI | Mantine |
|---|---|---|---|---|---|---|---|
Button | 6,9 KB | 14,6 KB | 15,7 KB | 34 KB | 122,4 KB | 45,6 KB | 23,7 KB |
Button + Select + DatePicker | 32,5 KB | 59,3 KB | 83,3 KB | 98,4 KB | 243,7 KB | 162,9 KB | 95,4 KB |
Table | 42,4 KB | 53,6 KB | 16,3 KB | 93,6 KB | 310,3 KB | 94,7 KB | 31,6 KB |
Y la misma pantalla —formulario con validación, tabla de pedidos con orden y paginación y un diálogo de confirmación— hecha con cuatro bibliotecas, pintada en el servidor e hidratada en Chromium con la CPU frenada cuatro veces (mediana de 15 cargas):
| Pantalla | Total al cargar | Sobre React solo | JS | CSS | Hidratación, mediana (mín.–máx.) | Recorrido | Fallos de axe |
|---|---|---|---|---|---|---|---|
| React sin biblioteca | 68,7 KB | — | 68,1 KB | 0,2 KB | 62 ms (51–95) | — | 0 |
| @amset/ui | 127,3 KB | +58,6 KB | 107,1 KB | 17,4 KB | 150 ms (122–352) | 6/6 | 0 |
| MUI | 219,6 KB | +150,9 KB | 210,8 KB | 0,2 KB | 242 ms (182–308) | 6/6 | 0 |
| Mantine | 175,7 KB | +107 KB | 156,6 KB | 15,1 KB | 149 ms (132–276) | 6/6 | 0 |
| antd | 390,6 KB | +321,9 KB | 343,9 KB | 0,2 KB | 352 ms (292–739) | 6/6 | 0 |
- No es una comparación de funciones. La
Tablede@amset/uiordena, filtra, agrupa, virtualiza y edita en celda; la de MUI y la de Mantine no hacen nada de eso por sí solas. Se mide peso. - El CSS de HeroUI y de shadcn no está en las piezas sueltas: lo genera Tailwind en cada aplicación. Por eso esas dos, y react-aria-components, que no trae estilos, no tienen pantalla equivalente. shadcn no es una biblioteca: se mide lo que arrastran sus piezas.
- MUI y antd meten el CSS dentro del JavaScript, y su HTML pesa más porque lo pintan dentro.
- Las pantallas de Mantine y antd cambian su tema: con el de fábrica suspenden el contraste AA. Se corrige con sus propios ajustes.
- El tiempo de hidratación depende de la máquina: vale para comparar las bibliotecas entre sí en la misma ejecución, no como cifra absoluta. La máquina no estaba en reposo; por eso se dan la mediana y el rango. Los pesos no dependen de eso.
- No se mide el tiempo de construcción, la memoria, el rendimiento al teclear o al ordenar miles de filas, ni el peso con otros empaquetadores.
| Biblioteca | Versiones medidas |
|---|---|
| @amset/ui | @amset/ui 0.16.0 |
| react-aria-components | react-aria-components 1.22.1 |
| shadcn/ui | @radix-ui/react-slot 1.5.0, @radix-ui/react-select 2.4.1, @radix-ui/react-popover 1.3.1, class-variance-authority 0.7.1, clsx 2.1.1, tailwind-merge 3.7.0, react-day-picker 10.0.2, date-fns 4.4.0, @tanstack/react-table 8.21.3 |
| HeroUI | @heroui/react 3.2.6, framer-motion 14.3.0 |
| antd | antd 6.6.6, @ant-design/cssinjs 2.1.2 |
| MUI | @mui/material 9.5.0, @mui/x-date-pickers 9.0.0-rc.0, @emotion/react 11.14.0, @emotion/styled 11.14.1, dayjs 1.11.23 |
| Mantine | @mantine/core 9.7.3, @mantine/dates 9.7.3, @mantine/hooks 9.7.3, dayjs 1.11.23 |
| Común a todas | react 19.3.1, react-dom 19.3.1, vite 6.4.4, playwright 1.63.0, axe-core 4.13.0 |
Ligera por defecto
- Un fichero por componente y
sideEffectslimitado a los.css: el empaquetador se lleva el JavaScript y el CSS de lo que importas, nada más. - Cada componente importa su propia hoja: no hay una hoja global que cargue toda la biblioteca en cada página.
- Los idiomas se cargan bajo demanda: con siete configurados se descarga uno.
- Las banderas van por regiones:
Flagpide el dibujo de la región de la bandera que pinta, no las de todo el mundo. - Los iconos se importan uno a uno: hay 2134 y solo pesan los que usas.
- Las capas que no están abiertas no montan su contenido: un selector de fecha cerrado no pinta su calendario.
Servidor, cliente e hidratación
Los componentes sin interacción se pueden usar desde un componente de servidor; los que la tienen llevan 'use client' lo más abajo posible. Ningún componente lee «hoy» ni «ahora» mientras se pinta, y los espacios que escribe Intl se normalizan: así el HTML del servidor y el del navegador coinciden aunque los pinten en días, zonas horarias o versiones de ICU distintas. Una prueba pinta cada ficha en un día y la hidrata en otro.
Seguridad
| Qué | Lo que hace |
|---|---|
| Dependencias | Ninguna al ejecutarse; React y React DOM son pares. La CI audita los avisos de seguridad y falla con uno alto o crítico. |
| Inyección de HTML | Ni dangerouslySetInnerHTML, ni innerHTML, ni eval, ni new Function en el código. |
Enlaces javascript: | Los bloquea React 19. La barra del editor rechaza también data: y cualquier esquema que no esté en su lista. |
| Enlaces a otra pestaña | Link y ButtonLink con target="_blank" llevan siempre rel="noopener noreferrer". |
| Red | La única petición que hace la biblioteca es la de Uploader, a la dirección que tú le das. |
| Almacenamiento | localStorage guarda el tema y, si se pide con persistKey, las columnas de una tabla. Nada más; ninguna cookie. |
Lo que te toca a ti: comprobar las direcciones que lleguen de un usuario antes de usarlas como href, y sanear en el servidor el HTML de un editor. Una vulnerabilidad se avisa con una incidencia confidencial en el proyecto amset/amset-ui de gitlab.amset.tech, nunca en una pública. Solo la última versión menor recibe arreglos.
Licencia
MIT: se puede usar en proyectos personales y comerciales, modificar y redistribuir, conservando el aviso de copyright.
