Encuesta sobre bibliotecas de componentes accesibles
cuáles superan realmente una auditoría axe
Instalamos siete de las bibliotecas de componentes React más descargadas en 2026, conectamos cada una a una aplicación nueva de Next.js 15 / React 19 / TypeScript y ejecutamos el mismo conjunto de pruebas de auditoría contra cada primitivo: axe-core 4.11 en Chromium sin cabeza, comprobaciones manuales de teclado, NVDA en Windows, VoiceOver en macOS y un análisis de accesibilidad de Lighthouse para el coste en tamaño de bundle.
1. El conjunto de pruebas de auditoría
Cada biblioteca se instaló en el mismo andamiaje de React 19 / Next.js 15 / TypeScript 5.5 siguiendo la ruta de instalación recomendada por el proveedor: npm i para las bibliotecas empaquetadas (Radix UI primitives, Headless UI 2.x, Mantine 8.x, Chakra UI v3, Ark UI, React Aria Components), y la CLI de shadcn para shadcn/ui — que copia el código fuente en components/ui en lugar de empaquetarlo. A continuación, montamos una página de demostración completa que exponía el conjunto completo de primitivos interactivos de cada biblioteca en su estado predeterminado, sin modificaciones de tema y sin envoltorios personalizados.
El conjunto de pruebas de auditoría se ejecutó en tres pasadas. La primera fue un análisis automatizado axe-core 4.11 mediante Playwright contra el DOM renderizado, con el conjunto completo de reglas WCAG 2.2 AA y las reglas experimentales habilitadas. La segunda fue una comprobación manual de teclado: tabulador, tabulador+mayúsculas, teclas de flecha, escape, intro, espacio e inicio/fin contra cada primitivo, puntuada conforme al contrato de teclado esperado según la Guía de Prácticas de Autoría WAI-ARIA. La tercera fue una prueba de humo con lector de pantalla con NVDA 2025.1 en Chrome y Safari/VoiceOver en macOS Sonoma, evaluando el anuncio de rol, el nombre accesible y el anuncio de estado al interactuar el usuario.
Se seleccionaron once patrones ARIA como superficie de evaluación para la matriz, porque son los patrones que aparecen en las interfaces de producto que generan demandas: diálogo, diálogo de alerta, combobox, listbox, menú, barra de menú, pestañas, acordeón, información emergente (tooltip), interruptor (switch) y control deslizante (slider). Una biblioteca que domina los botones y los encabezados pero entrega un combobox roto es una biblioteca que fallará una auditoría en cuanto un usuario real intente filtrar una lista de clientes.
Una aprobación axe significa cero infracciones de cualquier regla en la etiqueta WCAG 2.2 AA más la etiqueta experimental, renderizado con las props predeterminadas y el ejemplo de uso documentado por la biblioteca. No significa que la biblioteca sea infalible — axe detecta aproximadamente la mitad de todos los fallos WCAG — pero una biblioteca que no puede superar axe en su propia demo no puede superarlo en ningún otro lugar.
«El estado predeterminado es el único estado que la mayoría de los equipos de ingeniería ve nunca. Si una biblioteca entrega un valor predeterminado roto, ese valor predeterminado roto llega a producción.»
2. Siete bibliotecas, lado a lado
Tres de las siete bibliotecas — Radix UI, React Aria Components y Ark UI — superaron axe en todos los primitivos en su estado predeterminado sin necesidad de modificaciones. Headless UI superó axe en todos salvo el primitivo de menú, donde un aria-activedescendant faltante en el disparador de menú de estilo listbox generó una única infracción. shadcn/ui — que es en sí misma una capa fina sobre Radix UI — superó axe en todos los primitivos que ofrece, pero la salvedad es que solo ofrece aproximadamente dos tercios de la superficie de Radix, y las lagunas (combobox, listbox, barra de menú) son exactamente los patrones en los que los equipos cometen más errores de accesibilidad cuando los implementan a mano.
Mantine y Chakra UI v3 fueron las dos bibliotecas cuyos valores predeterminados generaron infracciones en axe. El combobox, el switch y el slider de Mantine generaron al menos una infracción axe en su ejemplo de uso documentado, principalmente por nombres accesibles faltantes en el input subyacente. Chakra UI v3 — que adoptó una arquitectura de máquinas de estado basada en Zag a finales de 2024 — corrigió muchos de los problemas de v2, pero sigue entregando un tooltip que se activa solo al pasar el cursor, lo que constituye una infracción de 1.4.13 Contenido en suspensión o en foco en axe y un riesgo de trampa de teclado en el modo virtual del lector de pantalla.
3. Matriz de cobertura de patrones
La cuadrícula de once patrones que se muestra a continuación es la referencia principal. Una celda verde significa que la biblioteca incluye el primitivo de forma nativa y supera axe en su estado predeterminado. Una celda amarilla significa que la biblioteca incluye el primitivo, pero al menos una infracción axe, una laguna en el contrato de teclado o una laguna en el lector de pantalla aparecieron en el ejemplo de uso documentado. Una celda gris «N/A» significa que la biblioteca no incluye ese primitivo — en el caso de shadcn/ui, son tres patrones para los que habría que importar Radix directamente o conectar un componente externo.
| Patrón | Radix | React Aria | Ark UI | shadcn | Headless | Mantine | Chakra v3 |
|---|---|---|---|---|---|---|---|
| Diálogo | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado |
| Diálogo de alerta | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Parcial | Aprobado |
| Combobox | Aprobado | Aprobado | Aprobado | N/A | Aprobado | Parcial | Aprobado |
| Listbox | Aprobado | Aprobado | Aprobado | N/A | Aprobado | Aprobado | Aprobado |
| Menú | Aprobado | Aprobado | Aprobado | Aprobado | Parcial | Aprobado | Aprobado |
| Barra de menú | Aprobado | Aprobado | Aprobado | N/A | N/A | Aprobado | Aprobado |
| Pestañas | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado |
| Acordeón | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado |
| Tooltip | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Parcial |
| Switch | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Parcial | Aprobado |
| Slider | Aprobado | Aprobado | Aprobado | Aprobado | Aprobado | Parcial | Aprobado |
Una celda gris N/A no es un fallo — es una cuestión de aprovisionamiento. La propuesta de shadcn/ui consiste en copiar el código fuente que se necesita de un conjunto curado y entregarlo; para los tres patrones N/A, se puede importar un primitivo de Radix directamente o extraerlo de un registro hermano. El riesgo en shadcn/ui no son los componentes que sí incluye — esos heredan la conformidad de Radix — sino los que no incluye, donde los equipos acaban implementando un combobox propio a deshoras para cumplir un plazo.
4. Contratos de teclado que fallaron
El fallo más repetible entre las bibliotecas no fue un atributo ARIA faltante — fue un contrato de teclado que casi coincidía con la guía APG y luego divergía en una tecla. El combobox de Mantine no responde a Inicio y Fin como especifica la APG. El tooltip de Chakra v3 no puede cerrarse con Escape cuando se abrió al pasar el cursor. El primitivo de menú de Headless UI se contrae en la primera pulsación de Flecha abajo en lugar de situar el foco en el primer elemento, porque la implementación trata el disparador como el descendiente activo al abrirse.
Estos no son casos extremos exóticos. Son los patrones que un usuario de lector de pantalla alcanza en el primer minuto. La comparación siguiente muestra la misma API de combobox escrita de dos formas — una con los valores predeterminados de Mantine y otra con React Aria Components — para ilustrar cómo es el contrato de teclado cuando se trata como una especificación y no como un elemento de acabado.
<Combobox
store={combobox}
onOptionSubmit={(v) => setValue(v)}
>
<Combobox.Target>
<InputBase
// sin conexión aria-controls en el input
// las teclas Inicio/Fin no mueven el foco dentro del listbox
// Flecha abajo abre pero no sitúa el foco en el elemento 1
value={value}
onChange={(e) => setValue(e.currentTarget.value)}
/>
</Combobox.Target>
<Combobox.Dropdown>
{/* los elementos del listbox se renderizan aquí */}
</Combobox.Dropdown>
</Combobox><ComboBox aria-label="Filter customers">
<Label>Customer</Label>
<Input />
<Popover>
<ListBox>
<ListBoxItem>Alpha</ListBoxItem>
<ListBoxItem>Bravo</ListBoxItem>
<ListBoxItem>Charlie</ListBoxItem>
</ListBox>
</Popover>
</ComboBox>
// aria-controls, aria-activedescendant,
// aria-expanded, role=combobox, Home/End,
// PageUp/PageDown, Escape: all wired by default.Las bibliotecas que derivan sus contratos de teclado de una especificación publicada — React Aria a partir de la WAI-ARIA APG, Ark UI a partir de las máquinas de estado de Zag.js — ofrecen esos contratos como el único comportamiento que admite el componente. Las bibliotecas que tratan el contrato de teclado como una lista de características entregan aproximadamente el 80 % de él y dejan el último 20 % como «trabajo futuro». Ese último 20 % es exactamente el conjunto de teclas que los usuarios de tecnología de apoyo presionan con más frecuencia.
5. Coste en tamaño de bundle por la accesibilidad
La objeción más habitual para elegir las bibliotecas más estrictas es el tamaño del bundle. La auditoría no lo confirmó. Los primitivos de Radix UI son descartables por árbol (tree-shakeable) por primitivo y se sitúan en el rango de aprox. 7-15 KB comprimido con gzip por unidad; React Aria Components es más pesado — aprox. 95 KB comprimido con gzip para el bundle completo — pero también es descartable por árbol. Headless UI es el más ligero con aprox. 25 KB comprimido con gzip para el paquete completo. Mantine y Chakra v3 son ambas soluciones con todo incluido e incluyen el sistema de estilos en el mismo bundle, situándolas en el rango de aprox. 180-220 KB comprimido con gzip de base.
La compensación es real pero menor de lo que sugiere el debate habitual. Un combobox que no respeta Inicio y Fin cuesta aproximadamente los mismos bytes que uno que sí lo hace. La elección no es «accesibilidad frente a rendimiento» — es «comportamiento derivado de la especificación frente a comportamiento implementado a mano», y la versión implementada a mano es con más frecuencia la más grande, porque lleva su propia máquina de estado ad hoc.
6. Guía para elegir el stack
Si el producto es una aplicación empresarial con un requisito de accesibilidad impuesto por la contratación, elegir React Aria Components.
Es la única biblioteca auditada cuyas APIs están explícitamente derivadas de la Guía de Prácticas de Autoría WAI-ARIA. El bundle es más pesado que Radix, pero la argumentación ante un revisor de VPAT es la más sencilla porque cada primitivo tiene una declaración de conformidad publicada.
Si el equipo es dueño de su propio sistema de diseño, elegir Radix UI (y opcionalmente shadcn/ui sobre él).
Radix proporciona primitivos sin estilos y conformes con la especificación. shadcn/ui facilita copiarlos e incorporar el tema. Hay que vigilar los tres patrones que shadcn no incluye — combobox, listbox, barra de menú — para los que se debería importar Radix directamente en lugar de implementarlos a mano.
Si el equipo trabaja principalmente con Tailwind y solo necesita una superficie reducida, elegir Headless UI — pero auditar el primitivo de menú en el propio código.
Headless UI es el bundle más pequeño del grupo y ofrece una superficie pequeña y bien probada. La única laguna en el primitivo de menú está documentada arriba; se puede corregir con una conexión explícita de aria-activedescendant en el menú de estilo listbox, o envolver el menú en un ayudante local del proyecto que lo haga.
Si el equipo valora tener todo incluido sobre la conformidad con la especificación, elegir Mantine o Chakra v3 — pero planificar las modificaciones.
Ambas bibliotecas permiten entregas rápidas y tienen buen aspecto de serie. Ambas también requieren modificaciones por componente para superar la auditoría en combobox, switch, slider (Mantine) o tooltip (Chakra v3). Hay que presupuestar el trabajo de modificación en el sprint de adopción de la biblioteca, no en el sprint en que se falla la auditoría.
Ejecutar axe contra la propia demo de la biblioteca antes de adoptarla.
Los proveedores mantienen sitios de demostración. Apuntar axe DevTools a ellos. Si la propia demo del proveedor genera infracciones en los primitivos que se planea utilizar, esas infracciones seguirán al producto. Esta única verificación de cinco minutos separa las bibliotecas que se adoptan de las que se evitan.
Conclusión: la especificación es el contrato
Las bibliotecas que superan una auditoría axe de forma limpia son aquellas cuyos autores trataron la Guía de Prácticas de Autoría WAI-ARIA como un contrato y no como una referencia. Radix UI, React Aria Components y Ark UI derivan cada una sus contratos de teclado y su conexión ARIA de una especificación publicada — la APG en el caso de Radix y React Aria, las máquinas de estado de Zag.js en el caso de Ark UI — y ofrecen la especificación completa, no un subconjunto de ella.
Las bibliotecas que fallan no lo hacen porque sus autores no se preocupen por la accesibilidad. Fallan porque el contrato de teclado fue tratado como una lista de características, y las listas de características acaban al 80 % en lugar del 100 %. El último 20 % — Inicio y Fin en un combobox, Escape para cerrar un tooltip abierto al pasar el cursor, gestión del foco en la primera pulsación de Flecha abajo en un menú — es la parte que nota el usuario.
La situación de shadcn/ui se sitúa de manera peculiar entre ambas categorías. Los componentes que ofrece heredan la derivación de la especificación de Radix y la superan. Los componentes que no ofrece son las lagunas donde los equipos implementan un combobox propio, y ese combobox propio es donde entra en la base de código la siguiente infracción axe. La solución no es elegir una biblioteca diferente — es importar Radix directamente para esos tres patrones y tratarlos con la misma seriedad que el resto del sistema de diseño.
Los equipos de ingeniería que adoptan una biblioteca deberían combinar la elección con el resto del kit de herramientas para desarrolladores en nuestra página de aterrizaje para desarrolladores, ejecutar un análisis gratuito de WCAG 2.2 en la demo de la biblioteca antes de llevarla a producción, y comparar el resultado con la referencia completa de criterios de conformidad WCAG 2.2.
«Elegir la biblioteca cuyos autores trataron la especificación como un contrato convierte la auditoría en un trámite. Elegir la biblioteca cuyos autores trataron la especificación como una referencia convierte la auditoría en un backlog.»