Y Tools

FAQ Accordion

תצוגה חיה

קוד להטמעה

1. HTML
<ul class="faq-accordion-list">
    <li class="faq-accordion-item">
        <h3 class="faq-accordion-title">
            <button type="button" class="faq-accordion-btn">
                כותרת השאלה הראשונה?
                <span class="faq-icon" aria-hidden="true"></span>
            </button>
        </h3>
        <div class="faq-accordion-content">
            <div class="faq-content-inner">
                כאן נכנסת התשובה המפורטת לשאלה. האקורדיון יחשב את הגובה אוטומטית.
            </div>
        </div>
    </li>
    <li class="faq-accordion-item">
        <h3 class="faq-accordion-title">
            <button type="button" class="faq-accordion-btn">
                כותרת השאלה השנייה?
                <span class="faq-icon" aria-hidden="true"></span>
            </button>
        </h3>
        <div class="faq-accordion-content">
            <div class="faq-content-inner">
                עוד תשובה מפורטת שתופיע בלחיצה אנימטיבית.
            </div>
        </div>
    </li>
</ul>
2. CSS
.faq-accordion-list {
    display: flex;
    width: 100%;
    gap: 12px;
    flex-direction: column;
    margin: 0 auto;
    padding: 0;
    list-style: none;
}
.faq-accordion-item {
    width: 100%;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-radius: 12px;
    overflow: hidden;
    transition: all 0.3s ease;
}
.faq-accordion-item.active {
    border-color: #16a34a;
    background: #f0fdf4;
}
.faq-accordion-btn {
    background: transparent;
    display: flex;
    width: 100%;
    align-items: center;
    padding: 20px 24px;
    gap: 20px;
    text-align: right;
    justify-content: space-between;
    cursor: pointer;
    border: none;
    color: #0f172a;
    font-family: inherit;
	font-size: inherit;
	font-weight: inherit;
	line-height: inherit;
    transition: all 0.2s ease;
}
.faq-accordion-btn:hover,
.faq-accordion-btn:focus-visible {
    background: rgba(15, 23, 42, 0.05);
}
.faq-accordion-btn:focus-visible {
	outline: 2px solid #16a34a;
	outline-offset: -2px;
}
.faq-accordion-title {
    font-size: 18px;
    font-weight: 500;
    line-height: 1.4;
    margin: 0;
}
.faq-icon {
    position: relative;
    width: 20px;
    height: 20px;
    flex-shrink: 0;
}
.faq-icon::before,
.faq-icon::after {
    background: #64748b;
    position: absolute;
    content: "";
    transition: all 0.3s ease;
}
.faq-icon::before {
    width: 16px;
    height: 2px;
    left: 2px;
    top: 9px;
}
.faq-icon::after {
    width: 2px;
    height: 16px;
    top: 2px;
    left: 9px;
}
.faq-accordion-item.active .faq-icon::before,
.faq-accordion-item.active .faq-icon::after {
    background: #16a34a;
}
.faq-accordion-item.active .faq-icon::before {
    transform: scale(0.8, 1);
}
.faq-accordion-item.active .faq-icon::after {
    transform: scale(1, 0);
}
.faq-accordion-content {
    width: 100%;
    overflow: hidden;
    transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.faq-accordion-item:not(.active) .faq-accordion-content {
    max-height: 0 !important;
	visibility: hidden;
	-webkit-transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0.4s;
	transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0.4s;
}
.faq-content-inner {
    color: #475569;
    font-size: 16px;
    line-height: 1.6;
    padding: 0 24px 24px 24px;
}
3. JavaScript
document.addEventListener("DOMContentLoaded", function() {
    const lists = document.querySelectorAll('.faq-accordion-list');
    if (!lists.length) return;

    // מונה משותף לכל העמוד - מבטיח מזהים ייחודיים גם כשיש כמה אקורדיונים
    let uid = 0;

    // עדכון ה-max-height של התוכן לפי הגובה האמיתי של התוכן הפנימי
    function updateHeight(content, inner) {
        if (!content || !inner) return;
        content.style.maxHeight = inner.offsetHeight + 'px';
    }

    // מעקב אחרי שינויי גובה (גופנים, תמונות, שינוי גודל מסך) ועדכון ה-max-height
    function watchHeight(content, inner) {
        if (!content || !inner) return;
        if ('ResizeObserver' in window) {
            new ResizeObserver(function() {
                updateHeight(content, inner);
            }).observe(inner);
            return;
        }
        updateHeight(content, inner);
        window.addEventListener('load', function() { updateHeight(content, inner); });
        window.addEventListener('resize', function() { updateHeight(content, inner); });
    }

    // הפעלת אקורדיון אחד: נגישות, גובה דינמי ולחיצה
    function initAccordion(list) {
        const items = list.querySelectorAll('.faq-accordion-item');
        if (!items.length) return;

        // לפי הנחיות W3C - role="region" רק כשיש עד 6 פריטים, כדי לא להציף את ה-landmarks
        const useRegion = items.length <= 6;

        items.forEach(item => {
            const btn = item.querySelector('.faq-accordion-btn');
            const content = item.querySelector('.faq-accordion-content');
            const inner = item.querySelector('.faq-content-inner');
            if (!btn || !content || !inner) return;

            uid++;
            const btnId = 'faq-btn-' + uid;
            const contentId = 'faq-text-' + uid;

            btn.id = btnId;
            btn.setAttribute('aria-controls', contentId);
            btn.setAttribute('aria-expanded', item.classList.contains('active') ? 'true' : 'false');

            content.id = contentId;
            if (useRegion) {
                content.setAttribute('role', 'region');
                content.setAttribute('aria-labelledby', btnId);
            }

            watchHeight(content, inner);

            btn.addEventListener('click', () => {
                const isActive = item.classList.contains('active');

                // סגירת שאר הפריטים באותו אקורדיון בלבד
                items.forEach(otherItem => {
                    otherItem.classList.remove('active');
                    const otherBtn = otherItem.querySelector('.faq-accordion-btn');
                    if (otherBtn) otherBtn.setAttribute('aria-expanded', 'false');
                });

                // פתיחת הפריט הנוכחי אם היה סגור
                if (!isActive) {
                    item.classList.add('active');
                    btn.setAttribute('aria-expanded', 'true');
                }
            });
        });
    }

    lists.forEach(initAccordion);
});