Ir al contenido
Portal de documentación del EGD
Menú de la sección

Accesibilidad de la interfaz del SGD (WCAG 2.2 AA)

Estándar técnico vigente del proyecto: accesibilidad/ESTANDAR_ACCESIBILIDAD_SGD_MINJUSDH_v1.1.md (WCAG 2.2 A + AA obligatorio, AAA progresivo). Este documento detalla las reglas por componente y las verificaciones realizadas.

Contraste con el código actual (15/10/2026): consultar el diagnóstico actualizado, §7 y su matriz A/AA/AAA. Las pruebas descritas abajo son históricas. La revisión actual identifica barreras y pruebas pendientes en instancias reales; no acredita conformidad integral. Teclado y alternativa al arrastre con puntero son requisitos distintos: una alternativa de teclado por sí sola no satisface 2.5.7.

Lote 1 implementado tras autorización: ver §8 del diagnóstico. N1/N2/N4/N7/N8 tienen correcciones en las fuentes y verificaciones estáticas/unitarias. Pruebas nuevas de navegador y lector pendientes; no equivale a cierre de conformidad.

Revisión integral del frontend del usuario final y de los componentes compartidos (5 de octubre de 2026). Ejemplo operable en /design-system/componentes (solo desarrollo), sección «Accesibilidad».

Referencias y criterio de conformidad

ReferenciaQué aportaQué no sustituye
LATAMIdentidad visual: paleta, tipografía, radios, densidad.Contraste, foco ni teclado.
Gob.peClaridad de servicio público: lenguaje simple, enlace «Saltar al contenido», foco visible, reducción de movimiento, alto contraste.Las comprobaciones de WCAG.

El objetivo normativo es WCAG 2.2 nivel AA (consultado en https://www.w3.org/TR/WCAG22/). Novedades de 2.2 aplicables: 2.4.11 foco no oculto, 2.5.7 arrastre y 2.5.8 tamaño de objetivo (24 px). 4.1.1 Parsing ya no existe. Las referencias de diseño orientan; ninguna se da por cumplida sin comprobación.

Reglas aplicadas por componente

  • Lista de opciones común (.sgd-listbox/.sgd-option): el resaltado de la opción activa y de la elegida se basa en estado (data-highlighted, data-active, data-selected, foco) y no en :hover; la elegida lleva marca (check) además del peso 500, sin depender solo del color. Estados «Buscando…», «Sin resultados.» y error (en rojo, con texto) como ListboxStatus. Axe sin violaciones con la lista abierta en LATAM claro/oscuro e Institucional oscuro (2026-10-08); sin probar con lector de pantalla.
  • Selectores con búsqueda (SearchableCombobox): patrón ARIA «combobox con lista» (role="combobox", aria-autocomplete="list", aria-expanded, aria-controls, aria-activedescendant; lista role="listbox" con opciones role="option"/aria-selected), nombre por la etiqueta flotante o aria-label, el foco no sale del campo, ↑/↓/Enter/Escape/Tab sin romper la edición de texto (3.2.2, 4.1.2), estados «Buscando…»/«Sin resultados.» como role="status". Ver components/selectores-busqueda.md.
  • Campos (FloatingUnderlineInput, MultiSelectCombobox): etiqueta persistente (la flotante o el título externo; el placeholder nunca es el único nombre), required con marca « *» visible, error con texto + icono (role="alert", aria-invalid, aria-describedby; las descripciones propias se suman al error), valores precargados y limpieza con botón de 24 px. El selector con chips no abre su lista al recibir foco (3.2.1): abre con clic, escritura o ↓; aria-controls solo existe con la lista abierta; su ventana emergente tiene nombre.
  • Filtros y favoritos (filter-panel.tsx): el desplegable es un dialog con nombre («Filtros y favoritos»); las opciones son role="checkbox" + aria-checked operables con Espacio/Enter; las categorías son Collapsible con aria-expanded/aria-controls; activo (aria-pressed) y por defecto (texto «Por defecto» en el nombre) se distinguen por separado; abrir el desplegable no marca nada. Cada acción de un favorito (editar, eliminar) es un botón con nombre propio que no aplica ni marca el favorito; aparecen al pasar el mouse o con foco en la fila, y en táctiles en un menú «Más acciones». Tras guardar, eliminar o cancelar una confirmación el foco pasa a un destino lógico (favorito nuevo, siguiente favorito, título «Favoritos», botón «Eliminar»). El panel lateral devuelve el foco al disparador.
  • Tablas (DataTable, table*.tsx): th scope="col" con nombre propio (aria-labelledby al texto visible, sin el valor del separador de ancho), aria-sort con ciclo asc→desc→asc, encabezados que se ajustan en lugar de truncarse, casillas con nombre por fila y «seleccionar todos» con estado mixed, selección solo por casilla, barra de acciones como región con nombre y recuento cortés (role="status"), buscador con aria-label, conteo de resultados anunciado solo cuando deja de cambiar (700 ms), separador de ancho operable con ← → Inicio (alternativa al arrastre, 2.5.7), región horizontal con nombre y foco solo cuando hay desbordamiento (TableScrollRegion), texto truncado (TruncatedText) alcanzable con Tab y con tooltip solo si realmente se corta.
  • Diálogos y paneles (DialogContent, SheetContent): nombre y descripción, foco dentro, Escape según la política (allowed/blocked: las ventanas de sesión siguen sin cerrarse), y devolución del foco al control que las abrió también cuando no hay Trigger (useFocusRestore).
  • Botones y tooltips: nombre accesible en iconos, tooltip con foco de teclado (aria-describedby), descartable con Escape; hover plano (no depende de @media (hover)); botón de cierre compartido de 44 px.
  • Avisos (Sileo): región aria-live="polite"; cada aviso recibe nombre (aria-label) y su botón «Cerrar notificación».
  • Navegación: enlace «Saltar al contenido principal» al inicio del shell del funcionario (#contenido-principal), nav con nombre.
  • Color y contraste: --sgd-input-border claro ≥ 3:1; error/destructivo corregido en Theme Adobe Spectrum e Institucional (claro #b42318, oscuro #ff9a90 con texto oscuro); tonos de etiqueta ≥ 4,5:1 también sobre fila seleccionada y seleccionada con hover.
  • Movimiento y alto contraste: regla global prefers-reduced-motion (sin animaciones, transiciones ni scroll suave); forced-colors da contorno a página actual, pulsado y fila seleccionada.
  • Objetivo táctil: casillas y «×» de chips con área de 24 px sin cambiar su tamaño visual.

Verificaciones realizadas

Herramientas: axe-core 4.13 (ya presente por eslint-plugin-jsx-a11y, sin dependencia nueva), Chrome instalado controlado por CDP (teclado, ratón, capturas y árbol de accesibilidad reales), ESLint (jsx-a11y) y tsc.

  • axe (WCAG 2/2.1/2.2 A y AA + buenas prácticas): 0 violaciones en 18 combinaciones (reposo, desplegable abierto con favorito y categorías expandidas, tabla con selección × 6 temas/modos). Quedan 3 avisos de contraste sobre las etiquetas de la demostración de casillas deshabilitadas (componente inactivo, exento de 1.4.3).
  • Teclado real: abrir/cerrar filtros, marcar opción, expandir categoría, Escape con devolución de foco, ordenar, seleccionar filas, ajustar ancho, selector de columnas, guardar/editar/eliminar/cancelar favorito, enlace «Saltar al contenido», diálogos (permitido, bloqueado, confirmación) y panel lateral (focos y Tab dentro del modal).
  • Árbol de accesibilidad (nombre, rol y estado calculados por el navegador): encabezados, casillas (mixed), región de tabla, desplegable, opciones, categorías, combobox, campo obligatorio, interruptor, favorito activo/por defecto y aviso.
  • Adaptación: viewport de 320 px (400 %) y 720 px (200 %) sin desbordamiento horizontal fuera de las regiones con desplazamiento propio; desplegable y panel lateral utilizables; espaciado de texto 1.4.12 sin recortes salvo las descripciones con line-clamp (consultables con foco/tooltip); movimiento reducido (duraciones ≈ 0); alto contraste (captura revisada).
  • Hover real con ratón (cursor de mano y fondo suave) en botón ghost, categorías y opciones.

Limitaciones y pendientes

  • Hallazgos actuales por inspección: N1–N9 y riesgos R1–R4 en el diagnóstico enlazado. Tras el lote 1, los editores de destinatarios/V°B° incluyen teclado y Subir/Bajar; falta reprueba real. El lote 2 agrega ancho numérico y +/- (N3), tabla diaria (N5), contraste oscuro corregido tras medición (N6) y navegación del visor por botones/teclado (N9). Evidencia y límites en §9 del diagnóstico. R1–R4, NVDA y flujos autenticados siguen pendientes.

  • No se probó con lector de pantalla real (NVDA, JAWS, Narrator, VoiceOver): solo árbol de accesibilidad y axe. Probar con NVDA + Firefox/Chrome antes de declarar conformidad.

  • No se verificaron en navegador las pantallas autenticadas (shell del funcionario con enlace «Saltar al contenido», navegación y la bandeja de Emisión): quedan comprobadas por código, ESLint y tsc. Tampoco las pantallas de /admin: solo los ejemplos del Design System que usan los mismos componentes compartidos.

  • Zoom comprobado emulando el ancho del viewport (720 y 320 px), no con zoom real del navegador ni con «solo texto».

  • hover: none no puede emularse en este Chrome; las reglas planas se verificaron con ratón real.

  • 2.4.11 (foco no oculto): sin barra fija sobre el contenido en estas pantallas, pero los avisos flotantes pueden cubrir contenido; no se verificó de forma exhaustiva.

  • Las fuentes (Inter e iconos Material Symbols) ya se alojan en el propio SGD (public/fonts, ver «Fuentes alojadas» en design-system-sgd.md): sin Google, los iconos no se ven como texto aunque la red bloquee esos dominios. Sigue pendiente, como mejora futura, sustituir la fuente de iconos por SVG incrustados.

  • Popovers del administrador sin nombre (selectores de entidad, ciudadano, ubicación, fecha de admin/) y combos fuera del alcance de esta revisión: pendientes.

  • Los tamaños de texto de ayuda de 12 px siguen siendo los del Design System; no se aumentaron.

Cómo repetir las comprobaciones

cd app
node node_modules/eslint/bin/eslint.js src
node scripts/check-icon-font.mjs        # iconos usados ⊆ fuente alojada
node node_modules/typescript/bin/tsc --noEmit -p .

axe-core está en app/node_modules/axe-core/axe.min.js: puede inyectarse en la página de pruebas (/design-system/componentes) y ejecutarse con axe.run(document, { runOnly: { type: 'tag', values: ['wcag2a','wcag2aa','wcag21aa','wcag22aa','best-practice'] } }) en los seis temas/modos.

PDF/firma y carga: corrección tras diagnóstico

La revisión del 15-oct-2026 confirmó barreras de lectura textual del PDF, selección del sello en otra página con teclado y controles anidados en Dropzone. El diagnóstico se entregó primero (§10 del informe compartido); tras la aprobación posterior se implementaron las tres correcciones (§11). Ese avance sustituye el estado previo «pendiente de implementar».

  • PDF: lectura por página con el visor oficial de PDF.js y formulario «Ubicar sello» con página y coordenadas reales, reutilizando Popover/Input/Button. Sin OCR, sin garantizar orden semántico del original, sin cambios del contrato de firma. Detalle en components/firma-digital.md.
  • Dropzone compartido: un único input type=file nativo sobre la superficie; el contenedor no es botón ni recibe foco. Etiqueta externa mediante id/htmlFor, o label para usos independientes; ayuda, estado y error asociados por aria-describedby, error con role=alert/aria-invalid, obligatoriedad y carga comunicadas. Quitar archivo devuelve el foco al input. Conservar tipos, límites, validaciones y callbacks de cada consumidor; no añadir otro control envolvente.
  • Reprueba focalizada: lectura de tres páginas (una sin texto), ubicación decimal en página 2, límites, zoom, bloqueo, errores de archivo y foco; cuatro pruebas del helper y muestra en seis apariencias con 0 violaciones axe. Incompletos automáticos y pruebas sin ejecutar quedan en §11; no equivalen a conformidad WCAG del flujo completo.
  • Pendiente: NVDA, zoom real, documentos con estructura compleja y recorrido protegido de QA. La muestra del Design System (#pdf-heading) no firma ni envía archivos y no sustituye esas pruebas.