This code emulates the accordion layout here, and uses Bootstrap 5.
See the Pen
Accordion with categories – Bootstrap 5 by Laura Sage (@ThePixelPixie)
on CodePen.
<span style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" data-mce-type="bookmark" class="mce_SELRES_start"></span><div class="faq-container container content mb-3"> <div class="row gx-5 justify-content-center"> <div class="col-12 p-5 content"> <section class="cd-faq js-cd-faq"> <ul class="cd-faq__categories m-0 p-0"> <?php $terms = get_terms( array("taxonomy" => "category") ); foreach ($terms as $term) : $posts = get_posts(["post_type" => "faq", "cat" => $term->term_id, "post_status" => "publish"]); ?> <li><a class="cd-faq__category cd-faq__category-selected truncate" href="#<?php echo $term->slug; ?>"><?php echo $term->name; ?></a></li> <?php wp_reset_postdata(); endforeach; ?> </ul> <!-- cd-faq__categories --> <div class="cd-faq__items"> <?php $terms2 = get_terms( array("taxonomy" => "category") ); foreach ($terms2 as $term2) : $posts2 = get_posts(["post_type" => "faq", "cat" => $term2->term_id, "post_status" => "publish"]); ?> <ul id="<?php echo $term2->slug; ?>" class="cd-faq__group m-0 p-0"> <li class="cd-faq__title"> <h2><?php echo $term2->name; ?></h2> </li> <?php foreach($posts2 as $post2) : $content = apply_filters('the_content',$post2->post_content); ?> <li class="cd-faq__item"> <a class="cd-faq__trigger" href="#0"><span><?php echo $post2->post_title; ?></span></a> <div class="cd-faq__content"> <div class="text-component"> <?php echo $content; ?> </div> </div> </li> <?php endforeach; ?> </ul> <?php wp_reset_postdata(); endforeach; ?> </div> <a href="#0" class="cd-faq__close-panel text-replace">Close</a> <div class="cd-faq__overlay" aria-hidden="true"></div> </section> </div> </div> </div><span style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" data-mce-type="bookmark" class="mce_SELRES_end"></span>
Here’s the CSS you need to add:
@import "https://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700"; body { font-size: 15px; background-color: #f2f2f2; } ul.cd-faq__categories, ul.cd-faq__group { list-style: none; border: 0; } .cd-faq { border: 0; display: block; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.085), 0 1px 8px rgba(0, 0, 0, 0.1); } .cd-faq::before { content: "mobile"; display: none; } .cd-faq a { text-decoration: none; font-weight: 300; transition: all .15s ease-in; } .cd-faq a:hover { color: rgba(255,255,255,.7); font-weight: 600; } .cd-faq .cd-faq__trigger:hover { color: #8f3985; } @media (min-width: 768px) { .cd-faq { position: relative; box-shadow: none; display: -ms-flexbox; display: flex; } .cd-faq::before { content: "desktop"; } } @media (min-width: 768px) { .cd-faq__categories { position: -webkit-sticky; position: sticky; -ms-flex-item-align: start; align-self: flex-start; -ms-flex-negative: 0; flex-shrink: 0; top: 20px; width: 20%; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.085), 0 1px 8px rgba(0, 0, 0, 0.1); margin-top: 1.25rem; } } @media (min-width: 992px) { .cd-faq__categories { width: 200px; } } .cd-faq__category { position: relative; display: block; height: 50px; line-height: 50px; padding: 0 2rem 0 1.05rem; color: #fff; background-color: #4e545a; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; border-bottom: 1px solid #565c63; } .cd-faq__category::before, .cd-faq__category::after { content: ""; position: absolute; top: 50%; right: 16px; display: inline-block; height: 1px; width: 10px; background-color: #7e868f; } .cd-faq__category::after { -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg); } li:last-child .cd-faq__category { border-bottom: none; } @media (min-width: 768px) { .cd-faq__category { font-weight: 600; padding: 0 1.25rem; transition: background 0.2s; } .cd-faq__category::before, .cd-faq__category::after { display: none; } .cd-faq__category:hover { background: #565c63; color: #fff; } } @media (min-width: 992px) { .cd-faq__category::before { display: block; top: 0; right: auto; left: 0; height: 100%; width: 3px; background-color: #8f3985; opacity: 0; transition: opacity 0.2s; } } @media (min-width: 992px) { .cd-faq__category-selected { background: #3f4348; } .cd-faq__category-selected:hover { background: #3f4348; } .cd-faq__category-selected::before { opacity: 1; } } .cd-faq__items { position: fixed; z-index: 1; height: 100%; width: 90%; top: 0; right: 0; background: #fff; padding: 0 1.25rem 1.25rem; overflow: auto; -webkit-overflow-scrolling: touch; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateZ(0) translateX(100%); transform: translateZ(0) translateX(100%); transition: -webkit-transform 0.3s; transition: transform 0.3s; transition: transform 0.3s, -webkit-transform 0.3s; } @media (min-width: 768px) { .cd-faq__items { position: static; height: auto; width: auto; -ms-flex-positive: 1; flex-grow: 1; overflow: visible; -webkit-transform: translateX(0); -ms-transform: translateX(0); transform: translateX(0); padding: 0 0 0 0.75rem; background: 0 0; } } .cd-faq__items--slide-in { -webkit-transform: translateX(0); -ms-transform: translateX(0); transform: translateX(0); } html:not(.js) .cd-faq__items { position: static; height: auto; width: 100%; -webkit-transform: translateX(0); -ms-transform: translateX(0); transform: translateX(0); } .cd-faq__group { display: none; } @media (min-width: 768px) { .cd-faq__group { display: block; padding-top: 1px; } } html:not(.js) .cd-faq__group, .cd-faq__group--selected { display: block; } .cd-faq__title { margin: 1.25rem 0; } .cd-faq__title h2 { text-transform: uppercase; font-weight: 700; color: #3f4348; } @media (min-width: 768px) { .cd-faq__title { margin-bottom: 0.75rem; } } @media (min-width: 768px) { .cd-faq__item { background: #fff; margin-bottom: 0.25em; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); transition: box-shadow 0.2s; } .cd-faq__item:hover { box-shadow: undefined; } @media (min-width: 768px) { .cd-faq__item:hover { box-shadow: 0 1px 10px #6b7d8e; } } .cd-faq__item:last-of-type { margin-bottom: 0; } } .cd-faq__trigger { display: block; position: relative; margin: 1.25rem 0 0.5rem; color: #8f3985; } @media (min-width: 768px) { .cd-faq__trigger { font-weight: 300; margin: 0; padding: 0.75rem 2rem 0.75rem 0.75rem; } .cd-faq__trigger::before, .cd-faq__trigger::after { content: ""; position: absolute; right: 24px; top: 50%; height: 2px; width: 13px; background: #8f3985; -webkit-backface-visibility: hidden; backface-visibility: hidden; transition: -webkit-transform 0.2s; transition: transform 0.2s; transition: transform 0.2s, -webkit-transform 0.2s; } .cd-faq__trigger::before { -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); right: 32px; } .cd-faq__trigger::after { -webkit-transform: rotate(-45deg); -ms-transform: rotate(-45deg); transform: rotate(-45deg); } .cd-faq__item-visible .cd-faq__trigger::before { -webkit-transform: rotate(-45deg); -ms-transform: rotate(-45deg); transform: rotate(-45deg); } .cd-faq__item-visible .cd-faq__trigger::after { -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); } } .cd-faq__content p { color: #6b7d8e; } @media (min-width: 768px) { .cd-faq__content { display: none; padding: 0 0.75em; overflow: hidden; } .cd-faq__content .text-component { padding-bottom: 1.25rem; } } .cd-faq__content--visible { display: block; } @media (min-width: 768px) { html:not(.js) .cd-faq__content { display: block; } } .cd-faq__close-panel { position: fixed; z-index: 2; display: block; top: 5px; right: -40px; height: 40px; width: 40px; -webkit-transform: translateZ(0); transform: translateZ(0); -webkit-backface-visibility: hidden; backface-visibility: hidden; transition: right 0.3s; color: #fff; } .cd-faq__close-panel::before, .cd-faq__close-panel::after { content: ''; position: absolute; top: 16px; left: 12px; display: inline-block; height: 3px; width: 18px; background: #6b7d8e; } .cd-faq__close-panel::before { -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); } .cd-faq__close-panel::after { -webkit-transform: rotate(-45deg); -ms-transform: rotate(-45deg); transform: rotate(-45deg); } @media (min-width: 768px) { .cd-faq__close-panel { display: none; } } .cd-faq__close-panel--move-left { right: 1.25rem; transition-delay: 0.3s; } .cd-faq__overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #4e545a; visibility: hidden; opacity: 0; transition: opacity 0.3s, visibility 0.3s; } @media (min-width: 768px) { .cd-faq__overlay { display: none; } } .cd-faq__overlay--is-visible { visibility: visible; opacity: 1; } .cd-header { height: 180px; background-color: #8f3985; } @media (min-width: 992px) { .cd-header { height: 240px; } } .cd-header h1 { font-size: 1.728rem; font-weight: 300; color: #fff; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } @media (min-width: 992px) { .cd-header { height: 240px; } } .cd-article-link { color: #586626; }
And finally, the js you need to add at the bottom of the file, before
// Utility function function Util() {} /* class manipulation functions */ Util.hasClass = function (el, className) { if (el.classList) return el.classList.contains(className); else return !!el.className.match(new RegExp("(\\s|^)" + className + "(\\s|$)")); }; Util.addClass = function (el, className) { var classList = className.split(" "); if (el.classList) el.classList.add(classList[0]); else if (!Util.hasClass(el, classList[0])) el.className += " " + classList[0]; if (classList.length > 1) Util.addClass(el, classList.slice(1).join(" ")); }; Util.removeClass = function (el, className) { var classList = className.split(" "); if (el.classList) el.classList.remove(classList[0]); else if (Util.hasClass(el, classList[0])) { var reg = new RegExp("(\\s|^)" + classList[0] + "(\\s|$)"); el.className = el.className.replace(reg, " "); } if (classList.length > 1) Util.removeClass(el, classList.slice(1).join(" ")); }; Util.toggleClass = function (el, className, bool) { if (bool) Util.addClass(el, className); else Util.removeClass(el, className); }; Util.setAttributes = function (el, attrs) { for (var key in attrs) { el.setAttribute(key, attrs[key]); } }; /* DOM manipulation */ Util.getChildrenByClassName = function (el, className) { var children = el.children, childrenByClass = []; for (var i = 0; i < el.children.length; i++) { if (Util.hasClass(el.children[i], className)) childrenByClass.push(el.children[i]); } return childrenByClass; }; /* Animate height of an element */ Util.setHeight = function (start, to, element, duration, cb) { var change = to - start, currentTime = null; var animateHeight = function (timestamp) { if (!currentTime) currentTime = timestamp; var progress = timestamp - currentTime; var val = parseInt((progress / duration) * change + start); // console.log(val); element.setAttribute("style", "height:" + val + "px;"); if (progress < duration) { window.requestAnimationFrame(animateHeight); } else { cb(); } }; //set the height of the element before starting animation -> fix bug on Safari element.setAttribute("style", "height:" + start + "px;"); window.requestAnimationFrame(animateHeight); }; /* Smooth Scroll */ Util.scrollTo = function (final, duration, cb) { var start = window.scrollY || document.documentElement.scrollTop, currentTime = null; var animateScroll = function (timestamp) { if (!currentTime) currentTime = timestamp; var progress = timestamp - currentTime; if (progress > duration) progress = duration; var val = Math.easeInOutQuad(progress, start, final - start, duration); window.scrollTo(0, val); if (progress < duration) { window.requestAnimationFrame(animateScroll); } else { cb && cb(); } }; window.requestAnimationFrame(animateScroll); }; /* Focus utility classes */ //Move focus to an element Util.moveFocus = function (element) { if (!element) element = document.getElementsByTagName("body")[0]; element.focus(); if (document.activeElement !== element) { element.setAttribute("tabindex", "-1"); element.focus(); } }; /* Misc */ Util.getIndexInArray = function (array, el) { return Array.prototype.indexOf.call(array, el); }; Util.cssSupports = function (property, value) { if ("CSS" in window) { return CSS.supports(property, value); } else { var jsProperty = property.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); return jsProperty in document.body.style; } }; /* Polyfills */ //Closest() method if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; } if (!Element.prototype.closest) { Element.prototype.closest = function (s) { var el = this; if (!document.documentElement.contains(el)) return null; do { if (el.matches(s)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType === 1); return null; }; } //Custom Event() constructor if (typeof window.CustomEvent !== "function") { function CustomEvent(event, params) { params = params || { bubbles: false, cancelable: false, detail: undefined }; var evt = document.createEvent("CustomEvent"); evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); return evt; } CustomEvent.prototype = window.Event.prototype; window.CustomEvent = CustomEvent; } /* Animation curves */ Math.easeInOutQuad = function (t, b, c, d) { t /= d / 2; if (t < 1) return (c / 2) * t * t + b; t--; return (-c / 2) * (t * (t - 2) - 1) + b; }; (function () { // FAQ Template - by CodyHouse.co var FaqTemplate = function (element) { this.element = element; this.sections = this.element.getElementsByClassName("cd-faq__group"); this.triggers = this.element.getElementsByClassName("cd-faq__trigger"); this.faqContainer = this.element.getElementsByClassName("cd-faq__items")[0]; this.faqsCategoriesContainer = this.element.getElementsByClassName( "cd-faq__categories" )[0]; this.faqsCategories = this.faqsCategoriesContainer.getElementsByClassName( "cd-faq__category" ); this.faqOverlay = this.element.getElementsByClassName("cd-faq__overlay")[0]; this.faqClose = this.element.getElementsByClassName( "cd-faq__close-panel" )[0]; this.scrolling = false; initFaqEvents(this); }; function initFaqEvents(faqs) { // click on a faq category faqs.faqsCategoriesContainer.addEventListener("click", function (event) { var category = event.target.closest(".cd-faq__category"); if (!category) return; var mq = getMq(faqs), selectedCategory = category.getAttribute("href").replace("#", ""); if (mq == "mobile") { // on mobile, open faq panel event.preventDefault(); faqs.faqContainer.scrollTop = 0; Util.addClass(faqs.faqContainer, "cd-faq__items--slide-in"); Util.addClass(faqs.faqClose, "cd-faq__close-panel--move-left"); Util.addClass(faqs.faqOverlay, "cd-faq__overlay--is-visible"); var selectedSection = faqs.faqContainer.getElementsByClassName( "cd-faq__group--selected" ); if (selectedSection.length > 0) { Util.removeClass(selectedSection[0], "cd-faq__group--selected"); } Util.addClass( document.getElementById(selectedCategory), "cd-faq__group--selected" ); } else { // on desktop, scroll to section if (!window.requestAnimationFrame) return; event.preventDefault(); var windowScrollTop = window.scrollY || document.documentElement.scrollTop; Util.scrollTo( document.getElementById(selectedCategory).getBoundingClientRect() .top + windowScrollTop + 2, 200 ); } }); // on mobile -> close faq panel faqs.faqOverlay.addEventListener("click", function (event) { closeFaqPanel(faqs); }); faqs.faqClose.addEventListener("click", function (event) { event.preventDefault(); closeFaqPanel(faqs); }); // on desktop -> toggle faq content visibility when clicking on the trigger element faqs.faqContainer.addEventListener("click", function (event) { if (getMq(faqs) != "desktop") return; var trigger = event.target.closest(".cd-faq__trigger"); if (!trigger) return; event.preventDefault(); var content = trigger.nextElementSibling, parent = trigger.closest("li"), bool = Util.hasClass(parent, "cd-faq__item-visible"); Util.toggleClass(parent, "cd-faq__item-visible", !bool); //store initial and final height - animate faq content height Util.addClass(content, "cd-faq__content--visible"); var initHeight = bool ? content.offsetHeight : 0, finalHeight = bool ? 0 : content.offsetHeight; if (window.requestAnimationFrame) { Util.setHeight(initHeight, finalHeight, content, 200, function () { heighAnimationCb(content, bool); }); } else { heighAnimationCb(content, bool); } }); if (window.requestAnimationFrame) { // on scroll -> update selected category window.addEventListener("scroll", function () { if (getMq(faqs) != "desktop" || faqs.scrolling) return; faqs.scrolling = true; window.requestAnimationFrame(updateCategory.bind(faqs)); }); } } function closeFaqPanel(faqs) { Util.removeClass(faqs.faqContainer, "cd-faq__items--slide-in"); Util.removeClass(faqs.faqClose, "cd-faq__close-panel--move-left"); Util.removeClass(faqs.faqOverlay, "cd-faq__overlay--is-visible"); } function getMq(faqs) { //get MQ value ('desktop' or 'mobile') return window .getComputedStyle(faqs.element, "::before") .getPropertyValue("content") .replace(/'|"/g, ""); } function updateCategory() { // update selected category -> show green rectangle to the left of the category var selected = false; for (var i = 0; i < this.sections.length; i++) { var top = this.sections[i].getBoundingClientRect().top, bool = top <= 0 && -1 * top < this.sections[i].offsetHeight; Util.toggleClass( this.faqsCategories[i], "cd-faq__category-selected", bool ); if (bool) selected = true; } if (!selected) Util.addClass(this.faqsCategories[0], "cd-faq__category-selected"); this.scrolling = false; } function heighAnimationCb(content, bool) { content.removeAttribute("style"); if (bool) Util.removeClass(content, "cd-faq__content--visible"); } var faqTemplate = document.getElementsByClassName("js-cd-faq"), faqArray = []; if (faqTemplate.length > 0) { for (var i = 0; i < faqTemplate.length; i++) { faqArray.push(new FaqTemplate(faqTemplate[i])); } } })();