Collapsible Nuevo
El componente hp-collapsible implementa el patrón WAI-ARIA Disclosure, permitiendo mostrar u ocultar contenido de manera accesible. Base ideal para FAQs, secciones expandibles y patrones de revelación de contenido.
Demostración
Sin estilos (solo base.css)
Así se ve hp-collapsible usando únicamente @headless-primitives/utils/base.css. El toggle, aria-expanded y visibilidad del contenido funcionan completamente.
Comportamiento sin estilos impuestos.
Con estilos personalizados
Es una librería de componentes headless que proveen la accesibilidad y comportamiento nativo, dejando total libertad creativa para el diseño visual.
<hp-collapsible class="faq-item">
<hp-collapsible-trigger class="faq-question">
¿Pregunta frecuente?
<span class="faq-icon">▼</span>
</hp-collapsible-trigger>
<hp-collapsible-content class="faq-answer">
<p>Respuesta detallada a la pregunta frecuente...</p>
</hp-collapsible-content>
</hp-collapsible>.faq-item {
border: 1px solid #e2e8f0;
border-radius: 8px;
overflow: hidden;
margin-bottom: 1rem;
}
.faq-question {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 16px 20px;
background: #f8fafc;
border: none;
cursor: pointer;
font-size: 16px;
font-weight: 600;
color: #1a202c;
transition: background-color 0.2s;
}
.faq-question:hover {
background: #f1f5f9;
}
.faq-question:focus {
outline: 2px solid #3b82f6;
outline-offset: -2px;
}
.faq-icon {
font-size: 14px;
transition: transform 0.2s;
color: #64748b;
}
.faq-answer {
padding: 20px;
background: white;
border-top: 1px solid #e2e8f0;
}
.faq-answer p {
margin: 0;
color: #475569;
line-height: 1.6;
}
hp-collapsible[open] .faq-icon {
transform: rotate(180deg);
}Instalación
pnpm add @headless-primitives/collapsiblenpm install @headless-primitives/collapsibleyarn add @headless-primitives/collapsiblebun add @headless-primitives/collapsibleFeatures
- ⌨️ Activación por teclado con
EnterySpace. - ♿️
aria-expanded,aria-controlsyaria-labelledbygestionados automáticamente. - 🎨 Sin estilos visuales (Headless).
- ⚡️ Controlable via atributo
openo propiedad JS. - 🔒 Estado
disabledpropagable al trigger.
Anatomía
<hp-collapsible>
<hp-collapsible-trigger></hp-collapsible-trigger>
<hp-collapsible-content></hp-collapsible-content>
</hp-collapsible>API Reference
hp-collapsible
Contenedor principal que gestiona el estado de expansión/contracción.
Atributos / Propiedades
| Atributo / Propiedad | Tipo | Por Defecto | Descripción |
|---|---|---|---|
open | boolean | false | Si está presente, el contenido está visible. |
disabled | boolean | false | Deshabilita todo el collapsible. |
Eventos
| Evento | Detalle | Descripción |
|---|---|---|
hp-open | { open: boolean } | Se dispara cuando el collapsible se abre. |
hp-close | { open: boolean } | Se dispara cuando el collapsible se cierra. |
hp-change | { open: boolean } | Se dispara en cualquier cambio de estado. |
hp-collapsible-trigger
Botón que controla la visibilidad del contenido.
Atributos / Propiedades
| Atributo / Propiedad | Tipo | Por Defecto | Descripción |
|---|---|---|---|
disabled | boolean | heredado | Heredado del contenedor hp-collapsible. |
Atributos ARIA gestionados automáticamente
role="button"— Asignado si no se especifica.aria-expanded— Sincronizado con el estadoopendel contenedor.aria-controls— Referencia al ID del contenido.aria-disabled— Sincronizado condisabled.tabindex="0"— Habilitado cuando no está deshabilitado.
hp-collapsible-content
Panel de contenido que se muestra u oculta según el estado.
Atributos ARIA gestionados automáticamente
role="region"— Asignado si no se especifica.aria-labelledby— Referencia al ID del trigger.data-state—"open"|"closed".data-hp-panel— Presente siempre (usado porbase.css).
Accesibilidad
Adhiere al patrón WAI-ARIA APG para Disclosure.
Navegación por teclado
| Tecla | Acción |
|---|---|
Enter | Abre/cierra el contenido. |
Space | Abre/cierra el contenido. |
Ejemplos
Control Programático
const collapsible = document.querySelector("hp-collapsible");
// Abrir programáticamente
collapsible.open = true;
// Escuchar cambios
collapsible.addEventListener("hp-change", (e) => {
console.log("Estado cambiado:", e.detail.open);
});Anidación
<hp-collapsible>
<hp-collapsible-trigger>Exterior</hp-collapsible-trigger>
<hp-collapsible-content>
<p>Contenido exterior...</p>
<hp-collapsible>
<hp-collapsible-trigger>Interior</hp-collapsible-trigger>
<hp-collapsible-content>
<p>Contenido anidado...</p>
</hp-collapsible-content>
</hp-collapsible>
</hp-collapsible-content>
</hp-collapsible>