Patrones de UI para Astro y Biblioteca de Componentes Portátiles
Esta guía define el catálogo estandarizado de componentes portátiles y listos para usar para sitios Astro.
Los ejemplos independientes usan el Modelo de Componente Portátil: cero dependencias npm externas, cero runtimes de frameworks de cliente (sin React/Vue), tokens CSS con nombres de espacio y fallbacks incorporados, y mejora progresiva. En proyectos con framework, conserva los requisitos semánticos y de interacción mientras adaptas la composición y el estilo al contrato seleccionado. Verifica la accesibilidad en el proyecto renderizado; una plantilla por sí sola no establece la conformidad con WCAG.
Contratos de comportamiento y composición con el framework
Para un componente en el índice siguiente, utiliza su contrato semántico y de interacción: soporte de teclado, gestión de foco, elementos nativos, nombres accesibles, actualizaciones de estado y mejora progresiva. El proyecto/framework seleccionado gobierna el estilo, los tokens, las importaciones y la composición del componente. Las instrucciones del usuario son la autoridad final.
Los ejemplos usan el modelo de componente portátil independiente a continuación. Úsalo al añadir un componente independiente sin un contrato de composición de framework. Cuando un proyecto tenga una biblioteca establecida, adapta el comportamiento usando sus primitivas apropiadas en lugar de duplicar sus botones, encabezados o controles de formulario. Preserva la semántica y el comportamiento requeridos mientras adaptas los envoltorios y las clases del ejemplo.
Para un proyecto construido sobre un framework de componentes (Lumos, por ejemplo), usa la composición y el estilo de ese framework; sus primitivas pueden importarse. La regla de importación cero independiente y los tokens de respaldo con nombres de espacio no anulan el contrato propio de un framework seleccionado.
El Modelo de Componente Portátil
Para componentes portátiles independientes, usa estas cinco reglas. En un framework seleccionado, preserva los requisitos de comportamiento y sigue su contrato de composición/estilo como se describe arriba:
- Cero Importaciones Externas/del Sitio: El archivo del componente NO debe importar diseños del sitio, botones ni bibliotecas de UI de terceros para el cliente. La única excepción catalogada es SelfHostedMap, que necesita un renderizador de mapas y un lector de teselas; su especificación lista los paquetes, y se instalan solo con la aprobación del propietario.
- Variables CSS con Nombres de Espacio y Fallbacks: Nunca hagas referencia directa a tokens del anfitrión (ej.
var(--color-brand)) dentro de la hoja de estilo del componente. Siempre escribevar(--comp-propiedad, <fallback>). - BEM con Ámbito y Propiedades CSS Lógicas: Usa nomenclatura de clases BEM (
.c-theme-toggle,.c-accordion__summary) y propiedades lógicas (inline-size,block-size,padding-inline,margin-block). - Mejora Progresiva Vainilla Idempotente: Los scripts deben ejecutarse al cargar y volverse a enlazar limpiamente si las Transiciones de Vista de Astro están activas (
document.addEventListener('astro:after-swap', init)). - Objetivos Táctiles y ARIA: Los botones y controles interactivos deben tener un tamaño mínimo de
44px(2.75rem) o48px(3rem) para objetivos táctiles, estados ARIA adecuados (aria-expanded,aria-selected,aria-pressed,aria-controls), y anillos de foco de teclado.
Índice de Componentes
| Componente | Archivo de Especificación | Propósito | Contrato Clave |
|---|---|---|---|
| 1. ThemeToggle | components/theme-toggle.md | Conmutador de tema claro/oscuro sin FOUC y con morphing SVG | Script <head> en línea + mapeo de tokens OKLCH |
| 2. MobileNavDrawer | components/mobile-nav-drawer.md | Cajón de navegación deslizable accesible con hamburguesa animada | Objetivos táctiles de 48px, cierre con tecla Escape, sin retraso de desenfoque GPU |
| 3. SearchBar | components/search-bar.md | Campo de búsqueda del lado del cliente con botón de borrado y locutor en vivo | rAF debouncing (INP óptimo), aria-live, coordinador de eventos personalizado |
| 4. FilterChips | components/filter-chips.md | Barra de filtros de múltiples categorías con estados presionados accesibles | role="group", aria-pressed, coordinador de eventos personalizado |
| 5. SearchFilterBar | components/search-filter-bar.md | Patrón compuesto que combina SearchBar y FilterChips | Barra de herramientas apilada precompuesta, diseños flex de múltiples columnas, ámbito compartido |
| 6. AccessibleModal | components/accessible-modal.md | Superposición de diálogo accesible usando <dialog> nativo de HTML5 | Capa superior nativa, clic en fondo, tecla Escape, restauración de foco |
| 7. AccessibleAccordion | components/accessible-accordion.md | Acordeón/Preguntas Frecuentes nativo con expansión suave mediante CSS Grid | <details name="..."> nativo, 0 KB JavaScript |
| 8. AccessibleTabs | components/accessible-tabs.md | Conmutador de pestañas WAI-ARIA para niveles de precios o vistas de múltiples paneles | Navegación con teclas de flecha (Izquierda/Derecha/Inicio/Fin) |
| 9. SocialShare | components/social-share.md | Barra de compartir en redes sociales priorizando la privacidad con Web Share API | 100% seguro para GDPR, 0 rastreadores, URLs de intención estáticas |
| 10. TableOfContents | components/table-of-contents.md | Tabla de contenidos para artículos extensos con scrollspy | Seguimiento de encabezados con IntersectionObserver, se empareja con un diseño de artículo |
| 11. AccessibleCarousel | components/accessible-carousel.md | Deslizador CSS nativo con scroll-snap para reseñas, tarjetas o logotipos | Deslizamiento táctil nativo (0 KB JS), botones accesibles Anterior/Siguiente |
| 12. InfiniteTicker | components/infinite-ticker.md | Marquesina infinita de logotipos/texto con pausa al pasar el ratón/enfocar | Cumple con WCAG 2.2.2, pista duplicada oculta con aria-hidden |
| 13. StatsCounter | components/stats-counter.md | Barra de contador de métricas basada en HTML con animación de desplazamiento ease-out | 0 CLS, fallback HTML estático, IntersectionObserver |
| 14. AddToCalendar | components/add-to-calendar.md | Enlace "Guardar la fecha" a un archivo iCalendar generado en tiempo de compilación | .ics estático del mismo origen + <a download>, RFC 5545 válido, 0 KB JS |
| 15. SelfHostedMap | components/self-hosted-map.md | Mapa de los lugares de una lista a partir de un extracto PMTiles autogestionado; marcadores numerados coinciden con la lista | MapLibre perezoso, ruta de teselas HTTP 206, mapa con aria-hidden y equivalentes de texto, sigue el tema. Necesita paquetes npm (aprobación del propietario) |
| 16. ClickableParent | components/clickable-parent.md | Tarjeta/fila completa clickeable a través de un enlace o botón real | Área de impacto extendida con ::after, controles secundarios elevados, anillo de foco en el contenedor, 0 KB JS |
| 17. Card | components/card.md | Tarjeta de contenido con medios, metadatos, cuerpo y acciones secundarias | DOM con encabezado primero, prop headingLevel, diseño con consultas de contenedor, contrato ClickableParent cuando está enlazada |
Puerta de Decisión para Componentes No Catalogados (Punto de Decisión Humano)
Cuando un requisito del proyecto o diseño solicite un componente de UI interactivo que no sea uno de los 17 componentes catalogados arriba (por ejemplo: un deslizador de comparación de imágenes Antes/Después, selector de fecha, selector de rango, asistente de pasos o reproductor multimedia personalizado):
[!IMPORTANTE] DETENTE Y PREGUNTA: El agente NUNCA debe instalar silenciosamente librerías de framework del lado del cliente (React, Vue, Svelte), importar paquetes npm de terceros no verificados, ni dejar bloques marcadores de posición de texto temporales (ej.
<div class="c-placeholder">).El agente DEBE pausar y presentar al propietario del proyecto tres opciones distintas:
- Opción A: Componente Vainilla Personalizado (Recomendado): Crear un componente
.astroa medida y sin dependencias que cumpla con el Contrato de Respaldo para Componentes a Medida a continuación.- Opción B: Línea Base HTML Estática: Implementar un diseño semántico puramente estático (ej. imágenes lado a lado o tarjetas apiladas estándar) con 0 KB JavaScript, omitiendo por completo la mejora interactiva.
- Opción C: Adaptación de un Patrón del Catálogo: Evaluar si un patrón existente del catálogo puede satisfacer el requisito (ej. adaptar
AccessibleModalen un lightbox de imágenes, oAccessibleTabsen una vista de paneles escalonados).
Contrato de Respaldo para Componentes a Medida
Cuando el propietario del proyecto apruebe la construcción de un componente no catalogado (Opción A), la implementación debe cumplir estas seis reglas; para adaptaciones con framework, usa las reglas de composición, nomenclatura de clases y tokens del framework para los puntos 3–4:
- HTML Semántico Primero: Anclar la interfaz a elementos HTML estándar antes de escribir JavaScript (ej.
<input type="range">para deslizadores,<details>para divulgación,<dialog>para superposiciones). - Cero Dependencias de Tiempo de Ejecución Externas: Cero runtimes de frameworks de cliente (sin React/Vue) y cero paquetes de widgets de UI de terceros. Escribe solo TypeScript/JavaScript vainilla cuando la interacción del navegador sea realmente necesaria.
- BEM con Ámbito y Propiedades CSS Lógicas: Usa nomenclatura BEM estándar (
.c-bloque,.c-bloque__elemento) y propiedades de diseño relativas al flujo (inline-size,block-size,padding-block,margin-inline,inset). - Tokens con Nombres de Espacio y Fallbacks: Nunca codifiques valores hexadecimales. Consume tokens semánticos del anfitrión o propiedades personalizadas con nombres de espacio y fallbacks sensatos (
var(--comp-color, var(--color-primary))). - Mejora Progresiva Sin JavaScript: El componente debe permanecer legible, accesible y operativo cuando el JavaScript del cliente esté deshabilitado. Usa
@media (scripting: none)o diseños de respaldo CSS nativos (ej. vistas lado a lado o apiladas) para que ningún contenido quede oculto. - Cumplimiento con WCAG 2.2 AA: Mantén objetivos táctiles mínimos de
44px(2.75rem), anillos:focus-visiblevisibles de alto contraste, nombres accesibles claros (aria-label,<label>), y asegura 0 violaciones de axe-core.
Guía de Carga Selectiva para Agentes
Cuando el usuario solicite implementar o editar uno de los componentes anteriores, no leas todo el catálogo. En su lugar, lee solo el archivo de especificaciones del componente específico necesario (ej. components/accessible-carousel.md).
Verificación de Integración
Verifica la especificación seleccionada en la salida construida/desplegada: semántica y nombres, comportamiento de teclado/foco, transiciones de estado, tratamiento sin JS, inicialización repetida y mapeo de tokens del anfitrión. Las reglas de empaquetado independiente solo se aplican a componentes independientes; los frameworks reutilizan sus primitivas. Ejecuta las comprobaciones/construcción/pruebas configuradas del proyecto y divulga las comprobaciones no disponibles o las brechas de cobertura. 44px es la convención de tamaño objetivo de esta biblioteca, no el umbral de WCAG AA en sí mismo.
Los popups de selección nativos siguen siendo la interfaz de usuario del navegador/SO a menos que el propietario apruebe las compensaciones de un combobox personalizado.