Skip to content

About

Widget de accesibilidad completo en un solo archivo, sin dependencias. 11 controles (alto contraste, dislexia, lector de voz, guía de lectura, cursor grande y más). Se integra en cualquier web en menos de 5 minutos. En convenio con Fundación Arupo. 🧡

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

5 Commits

Folders and files

Repository files navigation

♿ Accessibility Widget

Un widget de accesibilidad completo, en un solo archivo, sin dependencias. 11 controles reales de accesibilidad que se integran en cualquier web en menos de 5 minutos.

npm version License: MIT No dependencies Size Vanilla JS

Creado por Connexo (Ecuador) en el marco del convenio con la Fundación Arupo por la inclusión y la accesibilidad. Es de código abierto (MIT): úsalo, modifícalo y compártelo. Cuanta más gente lo integre, más personas con discapacidad podrán usar la web con comodidad. Ese es el objetivo. 🧡


📑 Índice


✨ ¿Qué hace?

Añade un botón flotante ♿ que abre un panel con 11 controles. Todo pensado para funcionar también en teléfono (táctil), y las preferencias del usuario se guardan solas entre visitas (localStorage).

# Control Qué hace
1 Tamaño de texto Escala la tipografía (100% → 150%).
2 Espaciado de línea Aumenta el interlineado.
3 Fuente para dislexia Tipografía legible + más espaciado entre letras/palabras (enfoque BDA/WebAIM/W3C).
4 Alto contraste Fondo negro, texto blanco, enlaces amarillos.
5 Blanco y negro Escala de grises total.
6 Resaltar enlaces Borde + subrayado en todo lo interactivo.
7 Guía de lectura Una franja clara sigue el cursor o el dedo y atenúa el resto.
8 Cursor grande Puntero XL de alto contraste (PNG; funciona hasta en Safari).
9 Lector de voz (TTS) Selecciona texto (o deslízalo en el móvil) y se lee en voz alta.
10 Desactivar animaciones Elimina el movimiento (respeta también prefers-reduced-motion).
11 Modo Visual Total Máximo contraste: fondo negro, texto amarillo.

🎬 Demo

Abre demo.html con doble clic (no necesita servidor) y prueba los 11 controles. El botón ♿ aparece en la esquina.


🚀 Instalación en 5 minutos

Opción A — CDN (no descargas nada) · recomendado

Añade una sola línea antes de </body>:

<!-- jsDelivr (desde npm) -->
<script src="https://cdn.jsdelivr.net/npm/connexo-accessibility-widget@1/a11y-widget.min.js" defer></script>

<!-- o unpkg -->
<script src="https://unpkg.com/connexo-accessibility-widget@1/a11y-widget.min.js" defer></script>

El @1 fija la versión mayor: recibes las correcciones de la 1.x sin que una futura 2.0 cambie tu sitio sin avisar. Para fijar una versión exacta usa, por ejemplo, @1.0.0.

Opción B — Alojándolo tú

  1. Copia a11y-widget.min.js (o a11y-widget.js sin minificar) a tu sitio.
  2. Añade antes de </body>:
<script src="/ruta/a11y-widget.min.js" defer></script>

Eso es todo. No hay que inicializar nada: el widget arranca solo. ✅

Una copia alojada por ti no se actualiza sola. Mira Actualizar el widget para saber cómo enterarte de las versiones nuevas y cómo ponerlas.


🧩 Guías de integración por plataforma

HTML plano
<!doctype html>
<html lang="es">
  <body>
    <!-- ...tu contenido... -->
    <script src="a11y-widget.min.js" defer></script>
  </body>
</html>
React (Vite / Create React App)

La forma más simple es cargar el script una sola vez al montar la app:

// App.jsx
import { useEffect } from 'react';

export default function App() {
  useEffect(() => {
    const s = document.createElement('script');
    s.src = 'https://cdn.jsdelivr.net/npm/connexo-accessibility-widget@1/a11y-widget.min.js';
    s.defer = true;
    document.body.appendChild(s);
    return () => { s.remove(); };
  }, []);

  return <>{/* ...tu app... */}</>;
}

O, más fácil aún, pega la etiqueta <script> directamente en index.html.

Next.js (App Router o Pages Router)

Usa el componente next/script:

// app/layout.js  (o pages/_app.js)
import Script from 'next/script';

export default function RootLayout({ children }) {
  return (
    <html lang="es">
      <body>
        {children}
        <Script
          src="https://cdn.jsdelivr.net/npm/connexo-accessibility-widget@1/a11y-widget.min.js"
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}
Vue 3
// main.js
const s = document.createElement('script');
s.src = '/a11y-widget.min.js';
s.defer = true;
document.body.appendChild(s);

O simplemente añade la etiqueta <script> en public/index.html.

Angular

En angular.json, agrégalo al array scripts:

"scripts": [
  "src/assets/a11y-widget.min.js"
]

(copia el archivo a src/assets/).

WordPress

Sin plugins: Apariencia → Editor de temas → footer.php, y antes de </body> pega:

<script src="https://cdn.jsdelivr.net/npm/connexo-accessibility-widget@1/a11y-widget.min.js" defer></script>

Con plugin (recomendado para no perderlo al actualizar el tema): usa "Insert Headers and Footers" / "WPCode" y pega la misma línea en el footer.

Shopify

Admin → Temas → Editar código → layout/theme.liquid, antes de </body>:

<script src="https://cdn.jsdelivr.net/npm/connexo-accessibility-widget@1/a11y-widget.min.js" defer></script>
Webflow / Squarespace / Wix

Ve a los ajustes de código personalizado del sitio (Custom Code → Footer) y pega la etiqueta <script> del CDN. En Webflow: Project Settings → Custom Code → Footer Code.

Google Tag Manager

Crea una etiqueta de tipo HTML personalizado, pega la etiqueta <script> del CDN y dispárala en All Pages.


🔄 Actualizar el widget

Cómo se actualiza depende de cómo lo instalaste:

Cómo lo cargas ¿Se actualiza solo? Qué hacer
Por CDN, sin versión o con @1 (lo que recomienda esta guía) Sí Nada. Recibes cada versión 1.x nueva; por la caché del CDN puede tardar hasta unas 12 horas.
Por CDN con una versión exacta (@1.2.0) No Cambia el número en la URL.
Copia en tu servidor (Opción B) No Descarga el archivo nuevo y reemplázalo (ver abajo).

Descargar la última versión. Abre esta dirección, guarda el archivo y súbelo en lugar del anterior:

https://cdn.jsdelivr.net/npm/connexo-accessibility-widget@latest/a11y-widget.min.js

Si tu sitio guarda archivos en caché, añade la versión a la dirección del script para que los navegadores bajen el nuevo: <script src="/js/a11y-widget.min.js?v=1.2.0" defer></script>.

¿Qué versión tengo? Abre tu página, abre la consola del navegador (F12) y escribe A11yWidget.version. Si responde undefined, tienes una versión anterior a la 1.2.0: actualízala.

Aviso de versión nueva (desde la 1.2.0). Las copias que no vienen de un CDN con versión móvil consultan, como máximo una vez por semana y por navegador, cuál es la última versión publicada. Si hay una más nueva:

  • aparece un aviso en la consola del navegador (F12);
  • si abres tu página añadiendo ?a11y-update a la dirección (https://tusitio.com/?a11y-update), el pie del panel muestra la versión que usas y si hay una nueva, con un enlace a esta sección.

Los visitantes normales no ven nada. También puedes preguntarlo por código:

A11yWidget.checkForUpdates().then(console.log);
// → { current: '1.2.0', latest: '1.3.0', updateAvailable: true }

Se apaga con data-update-check="false" (ver Configuración). Qué datos implica: ver Preguntas frecuentes.


⚙️ Configuración

Opcional. Por atributos en el <script>:

<script src="a11y-widget.min.js"
        data-accent="#ff6600"
        data-position="bottom-right"
        defer></script>

O por objeto global antes del script:

<script>
  window.A11yWidgetConfig = { accent: '#0066ff', position: 'bottom-left' };
</script>
<script src="a11y-widget.min.js" defer></script>
Opción Valores Por defecto
accent cualquier color CSS (hex, rgb…) #ff6600
position bottom-right · bottom-left · top-right · top-left bottom-right
storageKey nombre de la clave de localStorage a11y-settings
updateCheck false apaga el aviso de versión nueva (ver Actualizar) activo en copias alojadas por ti

Revisa la esquina antes de publicar. El botón ♿ queda por encima de todo (z-index máximo), así que si tu sitio ya tiene algo flotante en esa esquina —botón de "volver arriba", WhatsApp, chat, aviso de cookies— lo tapará. Cámbialo de esquina con position, o ponlo en tu menú (ver API de JavaScript).

Contraste del icono: el icono y los textos que van sobre el color accent se ponen en blanco o en casi negro automáticamente, según cuál se lea mejor (mínimo 3:1, WCAG 1.4.11). Con colores claros, como dorados o amarillos, el icono saldrá oscuro.


🧠 API de JavaScript

A11yWidget.open();   // abre el panel
A11yWidget.close();  // lo cierra
A11yWidget.get();    // → objeto con las preferencias actuales
A11yWidget.set({ highContrast: true, fontSize: 1.25 }); // aplica preferencias
A11yWidget.version;  // → '1.2.0' (la versión que estás usando)
A11yWidget.checkForUpdates(); // → Promise { current, latest, updateAvailable }

Útil, por ejemplo, para poner tu propio botón "Accesibilidad" en el menú:

<button onclick="A11yWidget.open()" aria-haspopup="dialog">Accesibilidad</button>

Si lo haces, oculta el botón flotante y elige el lado por el que se abre el panel (position con -right lo abre por la derecha, con -left por la izquierda):

<style>.a11y-launch { display: none !important; }</style>
<script src="…/a11y-widget.min.js" data-position="top-right" defer></script>

Al cerrar el panel, el foco vuelve a tu botón. Si tu botón no es un <button> de verdad (por ejemplo, un <div> con un clic), dale role="button", tabindex="0" y que responda a Enter y Espacio: si no, quien navega con teclado no podrá abrir el panel.


♿ Accesibilidad y estándares

Este widget está construido siguiendo buenas prácticas de la WCAG 2.1 y de la guía de la British Dyslexia Association:

  • Navegable por teclado: el panel es un role="dialog" con trampa de foco, se cierra con Esc y devuelve el foco al botón que lo abrió.
  • Semántica ARIA: aria-pressed en los interruptores, aria-label en los controles, foco visible en todo el sitio (:focus-visible).
  • Táctil primero: la guía de lectura y el lector de voz funcionan con el dedo en el móvil, no solo con ratón.
  • Respeta al sistema: honra prefers-reduced-motion del sistema operativo.
  • No intrusivo: todo es opt-in; al apagar cada modo, la página vuelve a su estado original. Las preferencias se guardan por usuario en localStorage.

Nota honesta: un widget ayuda muchísimo, pero no sustituye un sitio bien hecho (HTML semántico, textos alternativos en imágenes, contraste suficiente de base). Es un complemento potente, no una excusa. 🙂


🌐 Compatibilidad

  • Navegadores modernos: Chrome, Edge, Firefox y Safari (escritorio y móvil).
  • Lector de voz: usa la Web Speech API nativa. La calidad de la voz depende del dispositivo — Android e iOS traen voces muy naturales; en Windows con solo voces del sistema (SAPI) suena más básico. El widget elige automáticamente la mejor voz en español disponible.
  • Cursor grande: solo aplica en escritorio (en móvil no hay puntero). Se usan PNG en vez de cursores SVG justamente para que funcione también en Safari.

🎨 Personalización e idioma

  • Color de marca: cambia accent (ver Configuración). Internamente es la variable CSS --a11y-accent.
  • Textos / idioma: los textos están en español dentro del array CONTROLS en a11y-widget.js. Tradúcelos o edítalos ahí y vuelve a minificar con npm run build.
  • Estilos de los modos: son las reglas .a11y-* dentro del mismo archivo, fáciles de ajustar.

❓ Preguntas frecuentes

¿Rompe el diseño de mi sitio? No. Los modos son opt-in y su UI está aislada; al apagarlos, tu sitio queda igual que antes. Mientras están activos, ten en cuenta dos cosas:

  • Alto contraste y Modo Visual Total pintan de negro el fondo de todo lo que tiene texto. Las capas decorativas que van encima del contenido (ruido, scanlines, viñetas, degradados sobre fotos) se detectan solas —porque no reciben clics (pointer-events: none) o porque están posicionadas y no tienen texto ni controles— y se dejan transparentes, para que no tapen la página.
  • Tamaño de texto y Modo Visual Total agrandan la fuente base (<html> hasta 24 px). Si tus títulos usan rem dentro de contenedores con overflow: hidden, las palabras largas pueden recortarse. Comprueba tus títulos con el texto al 150 % (WCAG pide que el contenido aguante hasta 200 %).

¿Envía datos a algún servidor? No envía datos de tus visitantes ni de tu sitio. Todo ocurre en el navegador del usuario; las preferencias se guardan solo en su dispositivo (localStorage). Cero rastreo.

Hay una única conexión, y solo en copias alojadas por ti: para el aviso de versión nueva, cada navegador pide como máximo una vez por semana el package.json del widget a jsDelivr. Va sin cookies y sin Referer, así que jsDelivr solo ve la IP, como en cualquier descarga desde un CDN. Si prefieres cero conexiones, añade data-update-check="false". Si lo cargas desde el CDN sin versión o con @1, no se hace esa consulta.

¿Necesito build o npm? No. Es un archivo. npm/esbuild solo hacen falta si quieres editar y volver a minificar.

¿Puedo poner mi propio botón en vez del flotante? Sí: usa A11yWidget.open() desde cualquier botón tuyo y oculta el flotante (ver API de JavaScript).


🤝 Contribuir

Los aportes son bienvenidos: abre un issue o un pull request. Ideas útiles: más idiomas, más voces, nuevos controles. Al ser MIT, cualquier agencia puede adaptarlo a su marca.

Editar y reconstruir:

npm install      # instala esbuild (solo para build)
# edita a11y-widget.js
npm run build    # regenera a11y-widget.min.js

📄 Licencia y créditos

MIT — libre para usar, modificar y redistribuir. Ver LICENSE.

Hecho con 🧡 por Connexo (Ecuador) en convenio con la Fundación Arupo (fundacionarupo.org) por una web más inclusiva para las personas con discapacidad.

About

Widget de accesibilidad completo en un solo archivo, sin dependencias. 11 controles (alto contraste, dislexia, lector de voz, guía de lectura, cursor grande y más). Se integra en cualquier web en menos de 5 minutos. En convenio con Fundación Arupo. 🧡

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages