Puntuación por principios POUR
Hallazgos — Percepción
Contraste insuficiente en texto secundario y métricas de KPI
Dashboard principal · Tarjetas KPI · Tabla de pedidos
El texto de labels y valores secundarios (#9CA3AF sobre #1A1D27) presenta una ratio de contraste de 3.2:1, por debajo del mínimo de 4.5:1 exigido por WCAG 2.2 SC 1.4.3 para texto normal. Afecta a ~60% del contenido informativo del dashboard.
sobre fondo
#C4C9E2
#EF4444
#6B7280
<p className="text-gray-400"> Pedidos hoy </p> <span className="text-sm text-gray-500"> vs ayer </span>
<p className="text-slate-300"> Pedidos hoy </p> <span className="text-sm text-slate-400"> vs ayer </span>
Gráficos de rendimiento sin alternativa textual
Dashboard · Recharts LineChart, BarChart
Los gráficos SVG generados por Recharts carecen de aria-label, role="img" y <title>. Un usuario de lector de pantalla solo escucha "group" sin contexto alguno. Los datos del gráfico son críticos para la toma de decisiones.
<LineChart data={shipmentData} width={500} height={300} > ... </LineChart>
<div role="img" aria-label="Envíos diarios jun 2026: pico 1.240 el día 12" > <LineChart ...>... /* tabla de datos oculta */ <table className="sr-only"> ... </table> </div>
Hallazgos — Operabilidad
Botón "Exportar CSV" sin etiqueta accesible (icono-only)
Dashboard · Barra de acciones superiores
El botón de exportación muestra únicamente un icono SVG sin aria-label. NVDA/VoiceOver anuncia "botón" sin nombre descriptivo. Además, el SVG carece de aria-hidden="true", por lo que el lector intenta leer el contenido vectorial.
<button onClick={exportCSV} className="btn-icon" > <DownloadIcon /> </button>
<button onClick={exportCSV} aria-label="Exportar datos a CSV" className="btn-icon" > <DownloadIcon aria-hidden="true" focusable="false" /> </button>
Modal de filtros sin trampa de foco (focus trap)
Modal de filtros avanzados · Overlay
Al abrir el modal de filtros avanzados, el foco del teclado puede escapar al contenido de fondo. WCAG 2.2 SC 2.1.2 exige que el foco quede contenido dentro del modal y sea liberado mediante la tecla Escape o un botón de cierre explícito. Además, al cerrar, el foco no retorna al botón que lo abrió.
function FilterModal() { return ( <div className="modal"> <form>...</form> </div> ); }
import FocusTrap from 'focus-trap-react'; function FilterModal({ onClose }) { return ( <FocusTrap focusTrapOptions={{ returnFocusOnDeactivate: true, escapeDeactivates: true }} > <div role="dialog" aria-modal="true" aria-labelledby="modal-title" > <form>...</form> </div> </FocusTrap> ); }
Botones de acción en tabla inferiores a 24×24 CSS px
Tabla de pedidos recientes · Columna "Acciones"
Los botones de editar/eliminar en la columna de acciones miden 18×18 px. WCAG 2.2 introdujo SC 2.5.8 Target Size (Minimum) que exige un área mínima de 24×24 CSS pixels o espacio adicional equivalente (offset) para no solapar con otros objetivos.
.action-btn {
width: 18px;
height: 18px;
padding: 0;
}
.action-btn { /* Icono visual */ width: 18px; height: 18px; /* Área táctil 24×24 */ padding: 3px; min-width: 24px; min-height: 24px; }
Hallazgos — Comprensibilidad y Robustez
Tabla de pedidos sin encabezados semánticos <th>
Dashboard · Tabla "Pedidos recientes"
La tabla usa únicamente <div> con estilos CSS para simular una tabla. Los lectores de pantalla no pueden asociar datos con sus encabezados ni anunciar la posición de la celda. SC 1.3.1 (Info and Relationships) exige que la estructura lógica sea perceptible programáticamente.
<div className="table"> <div className="row header"> <div>ID</div> <div>Estado</div> <div>Importe</div> </div> </div>
<table> <caption className="sr-only"> Pedidos recientes </caption> <thead> <tr> <th scope="col">ID</th> <th scope="col">Estado</th> <th scope="col">Importe</th> </tr> </thead> </table>
Banner de alerta crítica comunica estado solo por color
Banner sistema · Indicadores de estado en tabla
El banner de "Sistema degradado" usa únicamente un fondo rojo para indicar criticidad. SC 1.4.1 prohíbe usar el color como único medio de transmitir información. Los usuarios con deuteranopia o protanopia no pueden distinguir el estado. Además, el banner carece de role="alert" para que los lectores de pantalla lo anuncien automáticamente.
<div className="bg-red-600 text-white p-3"> Sistema degradado </div>
<div role="alert" aria-live="assertive" className="bg-red-600 text-white p-3 border-l-4 border-red-900" > <span aria-hidden="true"> ⚠️ </span> <strong>CRÍTICO:</strong> Sistema degradado </div>
Hoja de ruta de correcciones
Checklist de validación post-corrección
axe DevTools — auditoría automática en CI/CD · WAVE — extensión de navegador · Colour Contrast Analyser — ratios precisos · NVDA + Chrome — prueba lectores pantalla Windows · VoiceOver + Safari — prueba macOS/iOS · Lighthouse — integración Vercel/CI