Saltar al contenido principal

Accesibilidad

El widget se ha construido para cumplir WCAG 2.2 AA. Esta página enumera lo que el widget hace por ti y lo que tu integración debe seguir respetando.

Cumplimiento por criterio​

Criterio WCAGImplementación
1.4.3 Contraste mínimoTokens light/dark con contraste ≥ 4.5:1 en texto y 3:1 en componentes UI.
1.4.10 ReflowLayout responsive sin scroll horizontal a 320 px.
1.4.13 Content on hover/focusTooltips dismissibles con blur y mouseLeave.
2.1.1 KeyboardToda la UI es accesible por teclado. Sin trampas.
2.1.2 No keyboard trapLos modales atrapan foco con escape vía Esc y restauración.
2.4.3 Focus orderOrden lógico: input → toolbar (voz/imagen) → resultados → filtros.
2.4.7 Focus visibleAnillos de foco con --nrn-primary a 4 px.
3.2.2 On inputEl submit no se dispara hasta que el usuario presiona Enter o el botón.
3.3.2 LabelsTodos los inputs tienen aria-label o <label> asociado.
4.1.2 Name, role, valuecombobox, listbox, option, dialog, status correctamente aplicados.
4.1.3 Status messagesCambios de estado anunciados con role="status" (resultados cargados, filtros aplicados).

Shadow DOM y herramientas asistivas​

El widget se monta en un Shadow DOM en modo open. Los lectores de pantalla modernos (NVDA, JAWS, VoiceOver, TalkBack) navegan correctamente entre los nodos del Shadow Tree y el documento del host.

TeclaAcción
Tab / Shift+TabMover foco entre elementos del widget.
EnterLanzar la búsqueda con la query del input. Activa botones y enlaces.
EscCerrar modal/drawer/dropdown abierto. Si no hay nada abierto, limpia la query.
↑ / ↓Navegar sugerencias y resultados.
← / →Navegar carouseles (top products, comparación, kit).
Cmd+K / Ctrl+KAtajo interno del widget para abrir el chat. Está hardcodeado (siempre activo) y no es configurable desde NeuroonWidgetConfig — no hay ningún método público openChat() que el host pueda invocar.

Focus trap en modales​

El widget incluye un focus trap genérico (createFocusTrap) que se activa al abrir cualquier dialog (búsqueda por voz, búsqueda por imagen, comparador, drawer de filtros, drawer de carrito). Comportamiento:

  • Al activarse, mueve el foco al primer elemento focuseable o al initialFocus declarado.
  • Cicla con Tab / Shift+Tab dentro del contenedor.
  • Al cerrarse, restaura el foco al elemento que lo abrió.

ARIA en componentes clave​

// SearchInput
<input
role="combobox"
aria-expanded={showSuggestions}
aria-controls="neuroon-suggestions"
aria-activedescendant={activeSuggestionId}
aria-autocomplete="list"
aria-label={t('search.inputAriaLabel')}
/>

<ul role="listbox" id="neuroon-suggestions" aria-label={t('suggestions.autocompleteAriaLabel')}>
<li role="option" aria-selected={isActive}>…</li>
</ul>

Las claves de aria-label viven en el bundle de i18n y se traducen al locale activo.

Reduced motion​

El widget respeta prefers-reduced-motion: reduce:

export function prefersReducedMotion(): boolean {
if (typeof window === 'undefined') return false
return window.matchMedia('(prefers-reduced-motion: reduce)').matches
}

Anuncios para screen reader​

El widget emite anuncios role="status" / aria-live="polite" cuando:

  • Los resultados terminan de cargar (Mostrando N de T productos).
  • Se aplica/quita un filtro (Filtro Marca: Apple aplicado).
  • Se añade/quita un producto del comparador.
  • El asistente IA termina de "pensar".

Las claves están bajo filters.filtersAndSuggestions, comparison.panelExpanded, cart.a11y.itemAdded, etc..

Inputs en mobile​

Todos los inputs tienen font-size >= 16px en mobile para evitar el auto-zoom de iOS. El widget también añade touch-action: manipulation y -webkit-text-size-adjust: 100% en el root para uniformizar el comportamiento entre navegadores.

Buenas prácticas para el host​

  • Evita encerrar el widget dentro de un contenedor con overflow: hidden que recorte modales — el widget renderiza modales en su propio portalContainer dentro del Shadow Root, pero si el host limita el position: fixed desde un ancestro con transform, el modal puede recortarse.
  • Si tu tema fuerza prefers-reduced-motion: reduce con un toggle propio, propaga la media query: el widget la lee de window.matchMedia directamente.
  • No reordenes nodos del shadow tree desde el host. El árbol está controlado por Preact.

Próximas lecturas​