Skip to content

Accesibilidad

Headless Primitives construye accesibilidad desde la capa más baja: cada componente es un Custom Element que implementa su patrón WAI-ARIA correspondiente. No es una capa añadida sobre el hecho — es la razón de existir de la librería.

Conformidad WCAG 2.1

El paquete de estilos (@headless-primitives/styles) garantiza contraste mínimo WCAG 2.1 AA en todos sus tokens por defecto:

CriterioRatio mínimoAplica a
1.4.3 Contrast (Minimum)4.5 : 1Texto normal, labels, descripciones
1.4.11 Non-text Contrast3 : 1Bordes de checkbox, radio, switch
1.4.3 excepción disabledexentoEstados disabled

Si reemplazas los tokens de color con los tuyos, la responsabilidad de contraste pasa a tu aplicación. Usa herramientas como Colour Contrast Analyser o la DevTools de tu navegador para verificar.


Roles y patrones ARIA

Cada componente implementa el patrón oficial de la WAI-ARIA Authoring Practices Guide:

ComponentePatrón WAI-ARIARoles asignados
hp-buttonButton Patternrole="button"
hp-accordionAccordion Patternrole="region" en paneles, aria-expanded en triggers
hp-checkboxCheckbox Patternrole="checkbox", aria-checked
hp-radio-groupRadio Group Patternrole="radiogroup", role="radio"
hp-switchSwitch Patternrole="switch", aria-checked
hp-tabsTabs Patternrole="tablist", role="tab", role="tabpanel"
hp-dialogDialog Patternrole="dialog", aria-modal, aria-labelledby
hp-alert-dialogAlert Dialog Patternrole="alertdialog"
hp-popoverDisclosure Patternaria-expanded, aria-controls
hp-tooltipTooltip Patternrole="tooltip", aria-describedby
hp-collapsibleDisclosure Patternaria-expanded, aria-controls
hp-toggle-groupToolbar Patternrole="group", aria-pressed por item
hp-progressProgressbar Patternrole="progressbar", aria-valuenow, aria-valuemin, aria-valuemax

Todos los componentes interactivos son completamente navegables sin ratón.

Teclas comunes

TeclaComportamiento
Tab / Shift+TabMover foco entre componentes
Enter / SpaceActivar botones, checkboxes, switches, triggers
EscapeCerrar dialogs, popovers, tooltips

Por componente

Accordion / Collapsible

TeclaComportamiento
Enter / SpaceExpande o colapsa el panel activo
TabMueve al siguiente trigger

Tabs

TeclaComportamiento
ArrowLeft / ArrowRightNavega entre tabs y activa automáticamente
Home / EndPrimer / último tab

Radio Group

TeclaComportamiento
ArrowUp / ArrowDownMueve selección entre opciones
ArrowLeft / ArrowRightIgual que arriba / abajo

Dialog / Alert Dialog

TeclaComportamiento
EscapeCierra el dialog
TabCicla el foco dentro del dialog (focus trap)
Shift+TabCicla en sentido inverso dentro del dialog

El focus trap está implementado nativamente — al abrir un dialog el foco entra automáticamente y no puede escapar hasta que se cierra.

Toggle Group

TeclaComportamiento
ArrowLeft / ArrowRightNavega entre items
Enter / SpaceActiva / desactiva el item enfocado

Gestión del foco

Foco inicial al abrir overlays

Los componentes hp-dialog, hp-alert-dialog y hp-popover mueven el foco automáticamente al abrirse:

  • Dialog / Alert Dialog: el foco va al primer elemento enfocable dentro del contenido.
  • Popover: el foco va al primer elemento enfocable dentro del panel.

Al cerrarse, el foco regresa al elemento que lo disparó (el trigger).

Focus ring

Todos los elementos interactivos tienen un :focus-visible configurado por base.css:

css
[data-hp-component]:focus-visible {
  outline: var(--hp-focus-outline-width) solid var(--hp-focus-outline-color);
  outline-offset: 2px;
}

Los valores por defecto (#2563eb, 2px) cumplen WCAG 2.4.11 (Focus Appearance, nivel AA). Puedes cambiarlos:

css
:root {
  --hp-focus-outline-color: #7c3aed; /* tu color de marca */
  --hp-focus-outline-width: 3px; /* más visible */
}

Textos ocultos para lectores de pantalla

Usa la clase .hp-visually-hidden (incluida en base.css) para añadir contexto a lectores de pantalla sin afectar el diseño visual:

html
<hp-button aria-label="Cerrar dialog">

  <span class="hp-visually-hidden">Cerrar</span>
</hp-button>

Esta clase implementa la técnica estándar de visually-hidden: el elemento existe en el DOM y es leído por asistentes, pero ocupa 1×1px y es invisible.


Pruebas de accesibilidad recomendadas

Además de las herramientas automáticas (axe, Lighthouse), valida manualmente:

  1. Navega con Tab únicamente — cada elemento interactivo debe ser alcanzable y operable.
  2. Prueba con un lector de pantalla — VoiceOver (macOS/iOS), NVDA (Windows), TalkBack (Android).
  3. Aumenta el zoom al 200% — el contenido no debe romperse ni quedar oculto.
  4. Activa prefers-reduced-motion — las animaciones deben desactivarse o simplificarse.

Lanzado bajo la MIT License.