<div class="accordion js-accordion-group ">
<div class="accordion__item js-accordion is-open" id="accordion-item-1">
<a href="#accordion-item-1" class="accordion__header js-accordion-control">
<div class="accordion__title">Accordion item 1 <svg class="icon accordion__header-icon">
<use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#accordion-open"></use>
</svg>
<svg class="icon accordion__header-icon--collapse accordion__header-icon">
<use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#accordion-collapse"></use>
</svg>
</div>
</a>
<div class="accordion__content js-accordion-content">
<div class="accordion__inner">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum quo voluptatum, accusantium exercitationem totam tempora error delectus libero commodi et. Similique vel exercitationem rerum distinctio itaque sunt voluptatibus enim sint.
</div>
</div>
</div>
<div class="accordion__item js-accordion " id="accordion-item-2">
<a href="#accordion-item-2" class="accordion__header js-accordion-control">
<div class="accordion__title">Accordion item 2 <svg class="icon accordion__header-icon">
<use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#accordion-open"></use>
</svg>
<svg class="icon accordion__header-icon--collapse accordion__header-icon">
<use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#accordion-collapse"></use>
</svg>
</div>
</a>
<div class="accordion__content js-accordion-content">
<div class="accordion__inner">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum quo voluptatum, accusantium exercitationem totam tempora error delectus libero commodi et. Similique vel exercitationem rerum distinctio itaque sunt voluptatibus enim sint.
</div>
</div>
</div>
<div class="accordion__item js-accordion " id="accordion-item-3">
<a href="#accordion-item-3" class="accordion__header js-accordion-control">
<div class="accordion__title">Accordion item 3 <svg class="icon accordion__header-icon">
<use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#accordion-open"></use>
</svg>
<svg class="icon accordion__header-icon--collapse accordion__header-icon">
<use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#accordion-collapse"></use>
</svg>
</div>
</a>
<div class="accordion__content js-accordion-content">
<div class="accordion__inner">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum quo voluptatum, accusantium exercitationem totam tempora error delectus libero commodi et. Similique vel exercitationem rerum distinctio itaque sunt voluptatibus enim sint.
</div>
</div>
</div>
</div>
{% set iconOpen %}
{% include '@icon' with {name: 'accordion-open', class: 'accordion__header-icon'}%}
{% endset %}
{% set iconCollapse %}
{% include '@icon' with {name: 'accordion-collapse', class: 'accordion__header-icon', modifier: 'accordion__header-icon--collapse'}%}
{% endset %}
<div class="accordion js-accordion-group {{ modifier }} {{ class }}">
{% if data.items %}
{% for item in data.items %}
<div class="accordion__item js-accordion {% if loop.first %}is-open{% endif %}" id="{{ item.id }}">
<a href="#{{ item.id }}" class="accordion__header js-accordion-control">
<div class="accordion__title">{{ item.title }}{{ iconOpen }}{{ iconCollapse }}</div>
</a>
<div class="accordion__content js-accordion-content">
<div class="accordion__inner">
{{ item.content }}
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{
"language": "en-US",
"data": {
"items": [
{
"id": "accordion-item-1",
"title": "Accordion item 1",
"content": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum quo voluptatum, accusantium exercitationem totam tempora error delectus libero commodi et. Similique vel exercitationem rerum distinctio itaque sunt voluptatibus enim sint."
},
{
"id": "accordion-item-2",
"title": "Accordion item 2",
"content": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum quo voluptatum, accusantium exercitationem totam tempora error delectus libero commodi et. Similique vel exercitationem rerum distinctio itaque sunt voluptatibus enim sint."
},
{
"id": "accordion-item-3",
"title": "Accordion item 3",
"content": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum quo voluptatum, accusantium exercitationem totam tempora error delectus libero commodi et. Similique vel exercitationem rerum distinctio itaque sunt voluptatibus enim sint."
}
]
}
}
.accordion {
box-shadow: 0 1px 0 0 var(--color-brand);
transition: $transition-duration $transition-easing;
transition-property: box-shadow;
}
.accordion__item {
transition: $transition-duration $transition-easing;
transition-property: box-shadow;
box-shadow: 0 -1px 0 0 var(--color-brand);
}
.accordion__header {
position: relative;
display: block;
background: transparent;
padding: 7px 16px;
transition: $transition-duration $transition-easing;
transition-property: background-color, color;
@include bp(sm-min) {
padding: 17px 32px;
}
.accordion__item:hover & {
@media (hover: hover) {
background-color: var(--color-brand);
color: var(--color-text-inverse);
}
}
.accordion &:before {
content: none;
}
.accordion &:after {
content: none;
}
}
.accordion__content {
display: none;
transition: $transition-duration $transition-easing;
transition-property: background-color, color;
color: var(--color-text);
html.no-js &,
.accordion__item.is-open > & {
display: block;
}
.accordion__item:hover & {
@media (hover: hover) {
background-color: var(--color-brand);
color: var(--color-text-inverse);
}
}
}
.accordion__title {
vertical-align: middle;
line-height: 24px;
margin-right: 28px;
}
.accordion__header-icon {
position: absolute;
vertical-align: middle;
right: 16px;
top: 0;
bottom: 0;
margin: auto;
transition: $transition-duration $transition-easing;
transition-property: fill;
visibility: visible;
.accordion__item.is-open & {
visibility: hidden;
}
@include bp(sm-min) {
right: 32px;
}
.accordion__item:hover & {
@media (hover: hover) {
fill: var(--color-text-inverse);
}
}
&.accordion__header-icon--collapse {
padding-top: 1px;
visibility: hidden;
.accordion__item.is-open & {
visibility: visible;
}
}
}
.accordion__inner {
padding: 7px 16px;
opacity: .6;
@include bp(sm-min) {
padding: 17px 32px;
}
}
import Helpers from '@helpers';
import './accordion.scss';
export enum AccordionAnimationType {
slide,
fadeAndSlide,
}
export enum AccordionAnimationDirection {
in,
out,
}
export interface IAccordionSettings {
openClass?: string;
accordionClass?: string;
groupClass?: string;
controlClass?: string;
contentClass?: string;
animationSlideTime?: number;
animationFadeTime?: number;
scrollDelay?: number;
animationSlideEase?: string;
animationFadeEase?: string;
animationType?: AccordionAnimationType;
openIcon?: string;
closeIcon?: string;
}
export const accordionSettings: IAccordionSettings = {
accordionClass: 'js-accordion',
animationFadeEase: 'swing',
animationFadeTime: 500,
animationSlideEase: 'swing',
animationSlideTime: 500,
animationType: AccordionAnimationType.slide,
closeIcon: 'accordion-open',
contentClass: 'js-accordion-content',
controlClass: 'js-accordion-control',
groupClass: 'js-accordion-group',
openClass: 'is-open',
openIcon: 'accordion-collapse',
scrollDelay: 500,
};
export default class Accordion {
settings: IAccordionSettings;
element: JQuery;
constructor(target: HTMLElement, settings: IAccordionSettings = {}) {
this.settings = jQuery.extend(accordionSettings, settings) as IAccordionSettings;
this.element = $(target);
}
getAccordion(): JQuery {
let accordion: JQuery;
if (this.element.hasClass(this.settings.accordionClass)) {
accordion = this.element.addClass(this.settings.accordionClass);
} else {
accordion = this.element.parents('.' + this.settings.accordionClass);
}
return accordion.length ? $(accordion.get(0)) : accordion;
}
toggle(accordion: JQuery = this.getAccordion()): void {
if (accordion.length) {
if (accordion.hasClass(this.settings.openClass)) {
this.close(accordion);
} else {
this.open(accordion);
}
}
}
open(accordion: JQuery = this.getAccordion(), recursive: boolean = false, initialLoad: boolean = false): void {
if (accordion && accordion.length) {
this.closeOpen(accordion, recursive);
const parent: JQuery = accordion.parents('.' + this.settings.accordionClass);
if (parent.length) {
const parentAccordion: Accordion = new Accordion(parent.get(0));
parentAccordion.open(null, true, initialLoad);
}
accordion.addClass(this.settings.openClass);
const content: JQuery = accordion.find('.' + this.settings.contentClass);
if (content.length) {
if (!recursive) {
setTimeout((): void => {
if (!Helpers.isOnScreen($(content.get(0)))) {
Helpers.scrollToTarget(accordion);
}
}, this.settings.scrollDelay);
}
}
if (!recursive && !initialLoad) {
this.animate(AccordionAnimationDirection.in, accordion);
}
}
}
close(accordion: JQuery = this.getAccordion(), recursive: boolean = false): void {
if (accordion.length) {
if (!recursive) {
this.animate(AccordionAnimationDirection.out, accordion, (): void => {
accordion.removeClass(this.settings.openClass);
});
} else {
accordion.removeClass(this.settings.openClass);
}
}
}
closeOpen(accordion: JQuery = this.getAccordion(), recursive: boolean = false): void {
let group: JQuery = accordion.parents('.' + this.settings.groupClass);
if (group.length) {
group = $(group.get(0));
const open: JQuery = group.find('> .' + this.settings.accordionClass + '.' + this.settings.openClass);
open.each((index: number, element: HTMLElement): void => {
this.close($(element), recursive);
});
}
}
animate(type: AccordionAnimationDirection, accordion: JQuery = this.getAccordion(), onComplete: () => void = null): void {
if (accordion.length) {
let content: JQuery = accordion.find('.' + this.settings.contentClass);
const triggerOnComplete: () => void = (): void => {
content.removeAttr('style');
if (onComplete) {
onComplete();
}
};
if (content.length) {
const contentHeight: string = content.get(0).offsetHeight + 'px';
content = content.length ? $(content.get(0)) : content;
switch (this.settings.animationType) {
case AccordionAnimationType.slide:
switch (type) {
case AccordionAnimationDirection.in:
content.stop().css({
height: 0,
}).animate({
height: contentHeight,
}, this.settings.animationFadeTime, this.settings.animationFadeEase, triggerOnComplete);
break;
case AccordionAnimationDirection.out:
content.stop().animate({
height: 0,
}, this.settings.animationSlideTime, this.settings.animationSlideEase, triggerOnComplete);
break;
}
break;
case AccordionAnimationType.fadeAndSlide:
switch (type) {
case AccordionAnimationDirection.in:
content.stop().css({
height: 0,
opacity: 0,
}).animate({
height: contentHeight,
}, this.settings.animationSlideTime, this.settings.animationSlideEase, (): void => {
content.stop().animate({
opacity: 1,
}, this.settings.animationFadeTime, this.settings.animationFadeEase, triggerOnComplete);
});
break;
case AccordionAnimationDirection.out:
content.stop().animate({
opacity: 0,
}, this.settings.animationFadeTime, this.settings.animationFadeEase, (): void => {
content.stop().animate({
height: 0,
}, this.settings.animationSlideTime, this.settings.animationSlideEase, triggerOnComplete);
});
break;
}
break;
}
}
}
}
}
function onControlClick(event: JQuery.Event): void {
event.preventDefault();
const accordion: Accordion = new Accordion(this);
accordion.toggle();
}
const onLoadHashCheck: () => void = (): void => {
if (window.location.hash && $(window.location.hash).length && $(window.location.hash).hasClass(accordionSettings.accordionClass)) {
const accordion: Accordion = new Accordion($(window.location.hash).get(0));
accordion.open(null, false, true);
}
};
$((): void => {
$(document).on('click', '.' + accordionSettings.controlClass, onControlClick);
onLoadHashCheck();
});