Accordion

Accordion item 1

Item 1

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Accordion item 2

Item 2

Duum dolore eu fugiat nudatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Accordion item 2

Item 3

Duis aute irure dolo

Html


<div class="accordion" data-accordion>
    <div class="accordion__item" data-accordion-item>
        <div class="accordion__item-head flex--space-between flex--vertical-center" data-accordion-head>
            <span class="accordion__item-title">Accordion item 1</span><span class="accordion__item-icon"></span>
        </div>
        <div class="accordion__item-body" data-accordion-body>
            <h2 class="accordion__item-body-headline">Item 1</h2>
            <p>
                Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
            </p>
        </div>
    </div>
    <div class="accordion__item" data-accordion-item>
        <div class="accordion__item-head flex--space-between flex--vertical-center" data-accordion-head>
            <span class="accordion__item-title">Accordion item 2</span><span class="accordion__item-icon"></span>
        </div>
        <div class="accordion__item-body" data-accordion-body>
            <h2 class="accordion__item-body-headline">Item 2</h2>
            <p>
                Duum dolore eu fugiat nudatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
            </p>
        </div>
    </div>
    <div class="accordion__item" data-accordion-item>
        <div class="accordion__item-head flex--space-between flex--vertical-center" data-accordion-head>
            <span class="accordion__item-title">Accordion item 2</span><span class="accordion__item-icon"></span>
        </div>
        <div class="accordion__item-body" data-accordion-body>
            <h2 class="accordion__item-body-headline">Item 3</h2>
            <p>
                Duis aute irure dolo
            </p>
        </div>
    </div>
</div>

Scss

		
// local vars
$accordion-padding: 5rem;
$accordion-icon-size: 3rem;
$accordion-padding--medium: 2.5rem;
$accordion-icon-size--medium: 1.5rem;

.accordion {
	&__item {
		background-color: $color-gray-wild-sand;
		margin-bottom: 2rem;
		overflow: hidden;
		transition: $transition;
	}

	&__item-head {
		cursor: pointer;
		height: 14rem;
		padding-left: $accordion-padding;
		padding-right: $accordion-padding;
	}

	&__item-title {
		font-size: 3rem;
	}

	&__item-icon {
		margin-top: 3rem;
		position: relative;
		width: $accordion-icon-size;
		height: $accordion-icon-size;

		&:after, &:before {
			content: '';
			position: absolute;
			top: 0;
			background-color: $color-black;
			height: .4rem;
			width: 100%;
		}

		&:before {
			transform: rotate(90deg);
			transition: $transition;
		}
	}

	&__item-body {
		padding: $accordion-padding;
		padding-top: 0;
	}

	&__item-body-headline {
		margin-top: 0;
	}
}

// transition
.accordion__item {
	&.is-active {
		.accordion__item-icon {
			&:before {
				transform: rotate(0);
			}
		}
	}
}

@include viewport-medium {
	.accordion {
		&__item {
			margin-bottom: 1.5rem;
		}

		&__item-head {
			height: 8rem;
			padding-left: $accordion-padding--medium;
			padding-right: $accordion-padding--medium;
		}

		&__item-title {
			font-size: 2.1rem;
		}

		&__item-icon {
			margin-top: 1.6rem;
			width: $accordion-icon-size--medium;
			height: $accordion-icon-size--medium;

			&:after, &:before {
				height: .3rem;
			}
		}

		&__item-body {
			padding: $accordion-padding--medium;
			padding-top: 0;
		}
	}
}

JavaScript


export class accordionModule {
	accordionList: NodeList = document.querySelectorAll("[data-accordion]");
	accordionArray: HTMLElement[] = Array.prototype.slice.call(this.accordionList);
	accordionItem: NodeList = document.querySelectorAll("[data-accordion-item]");
	accordionItemBody: HTMLDivElement = document.querySelector("[data-accordion-body]");
	activeClass: string = "is-active";
	constructor() {
		this.accordion();
		window.addEventListener("resize", this.accordion, false);
	}
	// get siblings helper function
	private getSiblings = (elem) => {
		let siblings = [];
		let sibling = elem.parentNode.firstChild;
		for (; sibling; sibling = sibling.nextSibling) {
			if (sibling.nodeType !== 1 || sibling === elem) continue;
			siblings.push(sibling);
		}
		return siblings;
	}

	private accordion = () => {
		// each accordion
		this.accordionArray.forEach((element: HTMLElement) => {

			const childAccordionItems: HTMLCollection = element.children;
			const childAccordionItemsArray: HTMLElement[] = Array.prototype.slice.call(childAccordionItems);
			// each accordion item
			childAccordionItemsArray.forEach((listElement: HTMLElement) => {
				// get height of header
				let getHeadHeight: number = listElement.querySelector("[data-accordion-head]").clientHeight;
				let getBodyHeight: number = listElement.querySelector("[data-accordion-body]").clientHeight;
				let totalHeight: number = getHeadHeight + getBodyHeight;

				// default height and active class
				listElement.style.height = getHeadHeight + "px";
				listElement.classList.remove(this.activeClass);

				// toggle accordion on click
				const childAccordionItemsClick = listElement.querySelector("[data-accordion-head]");
				childAccordionItemsClick.addEventListener("click", (e: Event) => {

					let clickedElmParent = (e.currentTarget as HTMLElement).parentElement;
					let clickedElmParentSiblings = this.getSiblings(clickedElmParent);

					// toggle active class
					clickedElmParent.classList.toggle(this.activeClass);

					// add new height to header
					clickedElmParent.style.height = totalHeight + "px";

					// remove active class from siblings and set height
					clickedElmParentSiblings.forEach((siblingsElm: HTMLElement) => {
						siblingsElm.classList.remove(this.activeClass);
						siblingsElm.style.height = getHeadHeight + "px";
					})
					// close other if not active
					if (!clickedElmParent.classList.contains(this.activeClass)) {
						clickedElmParent.style.height = getHeadHeight + "px";
					}
				});
			});
		});
	}
}