interactive
intermediate
faq
accordion
expandable
questions
answers
Categoría · Interactivo Nivel de Dificultad · Intermedio Publicado el · 20 de enero de 2025

Componente FAQ Acordeón

Un componente FAQ estilo acordeón clásico con animaciones suaves y secciones expandibles

#faq #accordion #expandable #questions #answers

Diseño Responsivo

Soporte para Modo Oscuro

No

líneas

Compatibilidad del Navegador

No

Componente FAQ Acordeón

Un componente FAQ estilo acordeón clásico con animaciones suaves, secciones expandibles y una interfaz de usuario intuitiva para mostrar preguntas frecuentes.

Características

  • Animaciones Suaves: Transiciones CSS para abrir/cerrar secciones
  • Expansión Simple/Múltiple: Opción para permitir una o múltiples secciones abiertas
  • Navegación por Teclado: Soporte completo de accesibilidad por teclado
  • Funcionalidad de Búsqueda: Búsqueda integrada para filtrar preguntas
  • Diseño Responsivo: Funciona perfectamente en todos los tamaños de dispositivo
  • Indicadores de Iconos: Señales visuales para estados expandidos/colapsados
  • Estilo Personalizable: Fácil de tematizar y personalizar
  • Auto-desplazamiento: Se desplaza automáticamente a las secciones abiertas

Estructura HTML

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Componente FAQ Acordeón</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="faq-container">
        
        <div class="faq-header">
            <h1>Preguntas Frecuentes</h1>
            <p>Encuentra respuestas a preguntas comunes sobre nuestros servicios</p>
            
            
            <div class="search-container">
                <input type="text" id="faqSearch" placeholder="Buscar preguntas..." class="search-input">
                <svg class="search-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                    <circle cx="11" cy="11" r="8"></circle>
                    <path d="m21 21-4.35-4.35"></path>
                </svg>
            </div>
            
            
            <div class="faq-controls">
                <button id="expandAll" class="control-btn">
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                        <polyline points="6,9 12,15 18,9"></polyline>
                    </svg>
                    Expandir Todo
                </button>
                <button id="collapseAll" class="control-btn">
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                        <polyline points="18,15 12,9 6,15"></polyline>
                    </svg>
                    Colapsar Todo
                </button>
            </div>
        </div>

        
        <div class="faq-accordion" id="faqAccordion">
            <div class="faq-item" data-category="general">
                <div class="faq-question" tabindex="0" role="button" aria-expanded="false">
                    <h3>¿Cuál es su política de devoluciones?</h3>
                    <div class="faq-icon">
                        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                            <line x1="12" y1="5" x2="12" y2="19"></line>
                            <line x1="5" y1="12" x2="19" y2="12"></line>
                        </svg>
                    </div>
                </div>
                <div class="faq-answer">
                    <div class="faq-content">
                        <p>Ofrecemos una política de devolución de 30 días para todos los artículos no utilizados en su empaque original. Simplemente contacte a nuestro equipo de servicio al cliente para iniciar una devolución, y le proporcionaremos una etiqueta de envío prepagada.</p>
                        <ul>
                            <li>Los artículos deben estar sin usar y en condición original</li>
                            <li>Se requiere el empaque original</li>
                            <li>Reembolso procesado dentro de 5-7 días hábiles</li>
                        </ul>
                    </div>
                </div>
            </div>

            <div class="faq-item" data-category="envio">
                <div class="faq-question" tabindex="0" role="button" aria-expanded="false">
                    <h3>¿Cuánto tiempo toma el envío?</h3>
                    <div class="faq-icon">
                        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                            <line x1="12" y1="5" x2="12" y2="19"></line>
                            <line x1="5" y1="12" x2="19" y2="12"></line>
                        </svg>
                    </div>
                </div>
                <div class="faq-answer">
                    <div class="faq-content">
                        <p>Los tiempos de envío varían dependiendo de su ubicación y el método de envío seleccionado:</p>
                        <div class="shipping-table">
                            <div class="shipping-row">
                                <span class="shipping-method">Envío Estándar</span>
                                <span class="shipping-time">5-7 días hábiles</span>
                            </div>
                            <div class="shipping-row">
                                <span class="shipping-method">Envío Express</span>
                                <span class="shipping-time">2-3 días hábiles</span>
                            </div>
                            <div class="shipping-row">
                                <span class="shipping-method">Envío Nocturno</span>
                                <span class="shipping-time">1 día hábil</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="faq-item" data-category="pago">
                <div class="faq-question" tabindex="0" role="button" aria-expanded="false">
                    <h3>¿Qué métodos de pago aceptan?</h3>
                    <div class="faq-icon">
                        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                            <line x1="12" y1="5" x2="12" y2="19"></line>
                            <line x1="5" y1="12" x2="19" y2="12"></line>
                        </svg>
                    </div>
                </div>
                <div class="faq-answer">
                    <div class="faq-content">
                        <p>Aceptamos todos los métodos de pago principales para hacer su experiencia de compra conveniente:</p>
                        <div class="payment-methods">
                            <div class="payment-item">
                                <strong>Tarjetas de Crédito:</strong> Visa, MasterCard, American Express, Discover
                            </div>
                            <div class="payment-item">
                                <strong>Billeteras Digitales:</strong> PayPal, Apple Pay, Google Pay
                            </div>
                            <div class="payment-item">
                                <strong>Transferencia Bancaria:</strong> Transferencias ACH y wire aceptadas
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="faq-item" data-category="cuenta">
                <div class="faq-question" tabindex="0" role="button" aria-expanded="false">
                    <h3>¿Cómo creo una cuenta?</h3>
                    <div class="faq-icon">
                        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                            <line x1="12" y1="5" x2="12" y2="19"></line>
                            <line x1="5" y1="12" x2="19" y2="12"></line>
                        </svg>
                    </div>
                </div>
                <div class="faq-answer">
                    <div class="faq-content">
                        <p>¡Crear una cuenta es rápido y fácil! Siga estos simples pasos:</p>
                        <ol>
                            <li>Haga clic en el botón "Registrarse" en la esquina superior derecha</li>
                            <li>Ingrese su dirección de correo electrónico y cree una contraseña segura</li>
                            <li>Verifique su dirección de correo electrónico haciendo clic en el enlace que le enviamos</li>
                            <li>Complete su perfil con su información de envío</li>
                            <li>¡Comience a comprar con su nueva cuenta!</li>
                        </ol>
                        <p><strong>Beneficios de tener una cuenta:</strong></p>
                        <ul>
                            <li>Proceso de pago más rápido</li>
                            <li>Historial de pedidos y seguimiento</li>
                            <li>Descuentos exclusivos para miembros</li>
                            <li>Funcionalidad de lista de deseos</li>
                        </ul>
                    </div>
                </div>
            </div>

            <div class="faq-item" data-category="soporte">
                <div class="faq-question" tabindex="0" role="button" aria-expanded="false">
                    <h3>¿Cómo puedo contactar al soporte al cliente?</h3>
                    <div class="faq-icon">
                        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                            <line x1="12" y1="5" x2="12" y2="19"></line>
                            <line x1="5" y1="12" x2="19" y2="12"></line>
                        </svg>
                    </div>
                </div>
                <div class="faq-answer">
                    <div class="faq-content">
                        <p>¡Estamos aquí para ayudar! Puede contactar a nuestro equipo de soporte al cliente a través de múltiples canales:</p>
                        <div class="contact-methods">
                            <div class="contact-item">
                                <div class="contact-icon">📧</div>
                                <div class="contact-info">
                                    <strong>Soporte por Email</strong>
                                    <p>soporte@ejemplo.com</p>
                                    <span>Respuesta dentro de 24 horas</span>
                                </div>
                            </div>
                            <div class="contact-item">
                                <div class="contact-icon">📞</div>
                                <div class="contact-info">
                                    <strong>Soporte Telefónico</strong>
                                    <p>1-800-123-4567</p>
                                    <span>Lun-Vie 9AM-6PM EST</span>
                                </div>
                            </div>
                            <div class="contact-item">
                                <div class="contact-icon">💬</div>
                                <div class="contact-info">
                                    <strong>Chat en Vivo</strong>
                                    <p>Disponible en nuestro sitio web</p>
                                    <span>Lun-Vie 9AM-6PM EST</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="faq-item" data-category="general">
                <div class="faq-question" tabindex="0" role="button" aria-expanded="false">
                    <h3>¿Ofrecen envío internacional?</h3>
                    <div class="faq-icon">
                        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                            <line x1="12" y1="5" x2="12" y2="19"></line>
                            <line x1="5" y1="12" x2="19" y2="12"></line>
                        </svg>
                    </div>
                </div>
                <div class="faq-answer">
                    <div class="faq-content">
                        <p>¡Sí! Enviamos a más de 50 países en todo el mundo. Las tarifas de envío internacional y los tiempos de entrega varían según el destino.</p>
                        <div class="international-info">
                            <div class="info-section">
                                <h4>Costos de Envío</h4>
                                <p>Calculados al finalizar la compra basados en peso y destino</p>
                            </div>
                            <div class="info-section">
                                <h4>Tiempo de Entrega</h4>
                                <p>7-21 días hábiles dependiendo de la ubicación</p>
                            </div>
                            <div class="info-section">
                                <h4>Aduanas y Aranceles</h4>
                                <p>Responsabilidad del cliente, varía por país</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        
        <div class="no-results" id="noResults" style="display: none;">
            <div class="no-results-icon">
                <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                    <circle cx="11" cy="11" r="8"></circle>
                    <path d="m21 21-4.35-4.35"></path>
                </svg>
            </div>
            <h3>No se encontraron preguntas</h3>
            <p>Intente ajustar sus términos de búsqueda o navegue todas las preguntas arriba.</p>
        </div>
    </div>

    <script src="script.js"></script>
</body>
</html>

Estilos CSS

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    padding: 20px;
}

.faq-container {
    max-width: 800px;
    margin: 0 auto;
    background: white;
    border-radius: 16px;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
    overflow: hidden;
}.faq-header {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    padding: 40px 30px;
    text-align: center;
}

.faq-header h1 {
    font-size: 2.5rem;
    font-weight: 700;
    margin-bottom: 8px;
}

.faq-header p {
    font-size: 1.1rem;
    opacity: 0.9;
    margin-bottom: 30px;
}.search-container {
    position: relative;
    max-width: 400px;
    margin: 0 auto 20px;
}

.search-input {
    width: 100%;
    padding: 12px 20px 12px 50px;
    border: none;
    border-radius: 25px;
    font-size: 16px;
    background: rgba(255, 255, 255, 0.2);
    color: white;
    backdrop-filter: blur(10px);
    transition: all 0.3s ease;
}

.search-input::placeholder {
    color: rgba(255, 255, 255, 0.7);
}

.search-input:focus {
    outline: none;
    background: rgba(255, 255, 255, 0.3);
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2);
}

.search-icon {
    position: absolute;
    left: 18px;
    top: 50%;
    transform: translateY(-50%);
    color: rgba(255, 255, 255, 0.7);
}.faq-controls {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
}

.control-btn {
    background: rgba(255, 255, 255, 0.2);
    border: none;
    color: white;
    padding: 8px 16px;
    border-radius: 20px;
    font-size: 14px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
    transition: all 0.3s ease;
    backdrop-filter: blur(10px);
}

.control-btn:hover {
    background: rgba(255, 255, 255, 0.3);
    transform: translateY(-1px);
}.faq-accordion {
    padding: 0;
}

.faq-item {
    border-bottom: 1px solid #e2e8f0;
    transition: all 0.3s ease;
}

.faq-item:last-child {
    border-bottom: none;
}

.faq-item.active {
    background: #f8fafc;
}

.faq-question {
    padding: 24px 30px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    transition: all 0.3s ease;
    outline: none;
}

.faq-question:hover {
    background: #f8fafc;
}

.faq-question:focus {
    background: #f1f5f9;
    box-shadow: inset 0 0 0 2px #667eea;
}

.faq-question h3 {
    font-size: 1.1rem;
    font-weight: 600;
    color: #1e293b;
    margin: 0;
    flex: 1;
    text-align: left;
}

.faq-icon {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: #667eea;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s ease;
    flex-shrink: 0;
    margin-left: 16px;
}

.faq-icon svg {
    color: white;
    transition: transform 0.3s ease;
}

.faq-item.active .faq-icon {
    background: #4f46e5;
    transform: rotate(45deg);
}

.faq-answer {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease;
}

.faq-item.active .faq-answer {
    max-height: 1000px;
}

.faq-content {
    padding: 0 30px 24px;
    color: #64748b;
    line-height: 1.6;
}

.faq-content p {
    margin-bottom: 16px;
}

.faq-content ul,
.faq-content ol {
    margin: 16px 0;
    padding-left: 20px;
}

.faq-content li {
    margin-bottom: 8px;
}.shipping-table {
    background: #f8fafc;
    border-radius: 8px;
    padding: 16px;
    margin: 16px 0;
}

.shipping-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid #e2e8f0;
}

.shipping-row:last-child {
    border-bottom: none;
}

.shipping-method {
    font-weight: 500;
    color: #374151;
}

.shipping-time {
    color: #667eea;
    font-weight: 500;
}.payment-methods {
    margin: 16px 0;
}

.payment-item {
    background: #f8fafc;
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 8px;
    border-left: 4px solid #667eea;
}

.payment-item strong {
    color: #374151;
    display: block;
    margin-bottom: 4px;
}.contact-methods {
    margin: 20px 0;
}

.contact-item {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 16px;
    background: #f8fafc;
    border-radius: 12px;
    margin-bottom: 12px;
}

.contact-icon {
    font-size: 24px;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: white;
    border-radius: 50%;
    flex-shrink: 0;
}

.contact-info strong {
    color: #374151;
    display: block;
    margin-bottom: 4px;
}

.contact-info p {
    margin: 0;
    color: #667eea;
    font-weight: 500;
}

.contact-info span {
    font-size: 14px;
    color: #64748b;
}.international-info {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin: 20px 0;
}

.info-section {
    background: #f8fafc;
    padding: 16px;
    border-radius: 8px;
    border-left: 4px solid #667eea;
}

.info-section h4 {
    color: #374151;
    margin-bottom: 8px;
    font-size: 16px;
}

.info-section p {
    margin: 0;
    font-size: 14px;
}.no-results {
    text-align: center;
    padding: 60px 30px;
    color: #64748b;
}

.no-results-icon {
    margin-bottom: 20px;
    opacity: 0.5;
}

.no-results h3 {
    font-size: 1.5rem;
    margin-bottom: 8px;
    color: #374151;
}

.no-results p {
    font-size: 1rem;
}@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.faq-item {
    animation: fadeIn 0.3s ease;
}@media (max-width: 768px) {
    body {
        padding: 10px;
    }
    
    .faq-container {
        border-radius: 12px;
    }
    
    .faq-header {
        padding: 30px 20px;
    }
    
    .faq-header h1 {
        font-size: 2rem;
    }
    
    .faq-question {
        padding: 20px;
    }
    
    .faq-content {
        padding: 0 20px 20px;
    }
    
    .faq-question h3 {
        font-size: 1rem;
    }
    
    .contact-item {
        flex-direction: column;
        text-align: center;
    }
    
    .international-info {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 480px) {
    .faq-header h1 {
        font-size: 1.75rem;
    }
    
    .faq-controls {
        flex-direction: column;
        align-items: center;
    }
    
    .control-btn {
        width: 100%;
        max-width: 200px;
        justify-content: center;
    }
}

Funcionalidad JavaScript

class AccordionFAQ {
    constructor() {
        this.accordion = document.getElementById('faqAccordion');
        this.searchInput = document.getElementById('faqSearch');
        this.expandAllBtn = document.getElementById('expandAll');
        this.collapseAllBtn = document.getElementById('collapseAll');
        this.noResults = document.getElementById('noResults');
        this.faqItems = Array.from(document.querySelectorAll('.faq-item'));
        
        this.init();
    }
    
    init() {
        this.bindEvents();
        this.setupKeyboardNavigation();
    }
    
    bindEvents() {

        this.accordion.addEventListener('click', (e) => {
            const question = e.target.closest('.faq-question');
            if (question) {
                this.toggleItem(question.parentElement);
            }
        });

        this.searchInput.addEventListener('input', (e) => {
            this.filterQuestions(e.target.value);
        });

        this.expandAllBtn.addEventListener('click', () => this.expandAll());
        this.collapseAllBtn.addEventListener('click', () => this.collapseAll());
    }
    
    setupKeyboardNavigation() {
        this.accordion.addEventListener('keydown', (e) => {
            const question = e.target.closest('.faq-question');
            if (!question) return;
            
            switch (e.key) {
                case 'Enter':
                case ' ':
                    e.preventDefault();
                    this.toggleItem(question.parentElement);
                    break;
                case 'ArrowDown':
                    e.preventDefault();
                    this.focusNext(question);
                    break;
                case 'ArrowUp':
                    e.preventDefault();
                    this.focusPrevious(question);
                    break;
                case 'Home':
                    e.preventDefault();
                    this.focusFirst();
                    break;
                case 'End':
                    e.preventDefault();
                    this.focusLast();
                    break;
            }
        });
    }
    
    toggleItem(item) {
        const isActive = item.classList.contains('active');
        const question = item.querySelector('.faq-question');
        
        if (isActive) {
            this.closeItem(item);
        } else {
            this.openItem(item);
        }

        question.setAttribute('aria-expanded', !isActive);

        if (!isActive) {
            setTimeout(() => {
                item.scrollIntoView({
                    behavior: 'smooth',
                    block: 'nearest'
                });
            }, 150);
        }
    }
    
    openItem(item) {
        item.classList.add('active');
        const answer = item.querySelector('.faq-answer');
        const content = item.querySelector('.faq-content');

        answer.style.maxHeight = content.scrollHeight + 'px';

        item.style.animation = 'fadeIn 0.3s ease';
    }
    
    closeItem(item) {
        item.classList.remove('active');
        const answer = item.querySelector('.faq-answer');
        answer.style.maxHeight = '0';
    }
    
    expandAll() {
        const visibleItems = this.faqItems.filter(item => 
            item.style.display !== 'none'
        );
        
        visibleItems.forEach((item, index) => {
            setTimeout(() => {
                if (!item.classList.contains('active')) {
                    this.openItem(item);
                    const question = item.querySelector('.faq-question');
                    question.setAttribute('aria-expanded', 'true');
                }
            }, index * 100);
        });
    }
    
    collapseAll() {
        const activeItems = this.faqItems.filter(item => 
            item.classList.contains('active')
        );
        
        activeItems.forEach((item, index) => {
            setTimeout(() => {
                this.closeItem(item);
                const question = item.querySelector('.faq-question');
                question.setAttribute('aria-expanded', 'false');
            }, index * 50);
        });
    }
    
    filterQuestions(searchTerm) {
        const term = searchTerm.toLowerCase().trim();
        let visibleCount = 0;
        
        this.faqItems.forEach(item => {
            const question = item.querySelector('h3').textContent.toLowerCase();
            const answer = item.querySelector('.faq-content').textContent.toLowerCase();
            
            const matches = question.includes(term) || answer.includes(term);
            
            if (matches || term === '') {
                item.style.display = 'block';
                visibleCount++;

                if (term !== '') {
                    this.highlightSearchTerm(item, term);
                } else {
                    this.removeHighlights(item);
                }
            } else {
                item.style.display = 'none';

                if (item.classList.contains('active')) {
                    this.closeItem(item);
                }
            }
        });

        if (visibleCount === 0 && term !== '') {
            this.noResults.style.display = 'block';
            this.accordion.style.display = 'none';
        } else {
            this.noResults.style.display = 'none';
            this.accordion.style.display = 'block';
        }
    }
    
    highlightSearchTerm(item, term) {
        const question = item.querySelector('h3');
        const content = item.querySelector('.faq-content');

        const highlightText = (element) => {
            const text = element.textContent;
            const regex = new RegExp(`(${term})`, 'gi');
            const highlightedText = text.replace(regex, '<mark>$1</mark>');
            
            if (text !== highlightedText) {
                element.innerHTML = highlightedText;
            }
        };
        
        highlightText(question);
    }
    
    removeHighlights(item) {
        const marks = item.querySelectorAll('mark');
        marks.forEach(mark => {
            mark.outerHTML = mark.textContent;
        });
    }
    
    focusNext(currentQuestion) {
        const questions = Array.from(document.querySelectorAll('.faq-question'));
        const visibleQuestions = questions.filter(q => 
            q.closest('.faq-item').style.display !== 'none'
        );
        const currentIndex = visibleQuestions.indexOf(currentQuestion);
        const nextIndex = (currentIndex + 1) % visibleQuestions.length;
        visibleQuestions[nextIndex].focus();
    }
    
    focusPrevious(currentQuestion) {
        const questions = Array.from(document.querySelectorAll('.faq-question'));
        const visibleQuestions = questions.filter(q => 
            q.closest('.faq-item').style.display !== 'none'
        );
        const currentIndex = visibleQuestions.indexOf(currentQuestion);
        const prevIndex = currentIndex === 0 ? visibleQuestions.length - 1 : currentIndex - 1;
        visibleQuestions[prevIndex].focus();
    }
    
    focusFirst() {
        const firstVisible = document.querySelector('.faq-item:not([style*="display: none"]) .faq-question');
        if (firstVisible) firstVisible.focus();
    }
    
    focusLast() {
        const questions = Array.from(document.querySelectorAll('.faq-question'));
        const visibleQuestions = questions.filter(q => 
            q.closest('.faq-item').style.display !== 'none'
        );
        const lastVisible = visibleQuestions[visibleQuestions.length - 1];
        if (lastVisible) lastVisible.focus();
    }
}

document.addEventListener('DOMContentLoaded', () => {
    new AccordionFAQ();

    document.documentElement.style.scrollBehavior = 'smooth';

    const faqItems = document.querySelectorAll('.faq-item');
    faqItems.forEach((item, index) => {
        item.style.opacity = '0';
        item.style.transform = 'translateY(20px)';
        
        setTimeout(() => {
            item.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
            item.style.opacity = '1';
            item.style.transform = 'translateY(0)';
        }, index * 100);
    });
});

Ejemplos de Uso

Implementación Básica


const faq = new AccordionFAQ();

faq.openItem(document.querySelector('.faq-item[data-category="general"]'));

faq.filterQuestions('envío');

Configuración Personalizada


const faq = new AccordionFAQ({
    allowMultiple: true,        // Permitir múltiples elementos abiertos
    autoClose: false,          // No cerrar automáticamente otros elementos
    animationDuration: 300,    // Duración de animación en ms
    scrollOffset: 100,         // Desplazamiento al abrir elementos
    highlightSearch: true      // Resaltar términos de búsqueda
});

Integración con Analytics


class AnalyticsAccordionFAQ extends AccordionFAQ {
    toggleItem(item) {
        super.toggleItem(item);
        
        const question = item.querySelector('h3').textContent;
        const isOpening = item.classList.contains('active');

        gtag('event', 'faq_interaction', {
            'question': question,
            'action': isOpening ? 'open' : 'close'
        });
    }
}

Compatibilidad del Navegador

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+

Características Incluidas

✅ Animaciones suaves de acordeón
✅ Funcionalidad de búsqueda con resaltado
✅ Soporte de navegación por teclado
✅ Controles expandir/colapsar todo
✅ Auto-desplazamiento a secciones abiertas
✅ Diseño responsivo
✅ Atributos de accesibilidad ARIA
✅ Opciones de estilo personalizado
✅ Sin dependencias externas
✅ Estructura amigable para SEO
✅ Interfaz táctil amigable
✅ Animaciones de carga

Opciones de Personalización

  • Colores: Modificar propiedades personalizadas CSS para tematización
  • Velocidad de Animación: Ajustar duraciones de transición
  • Diseño: Personalizar espaciado y tipografía
  • Iconos: Reemplazar iconos SVG con personalizados
  • Búsqueda: Configurar comportamiento de búsqueda y resaltado
  • Teclado: Personalizar atajos de teclado

Este componente FAQ acordeón proporciona una forma profesional y amigable para el usuario de mostrar preguntas frecuentes con animaciones suaves y soporte completo de accesibilidad.

Fragmentos de Código Relacionados

Explora packs de plantillas

¿Necesitas bloques más grandes? Descubre landings y colecciones de componentes.

Abrir la biblioteca de plantillas ->