JSFiddle - React, Tailwind, and code Playground
by seulbiLee
HTML
<div class="wrap-accordion-group" data-role="accordion-group" accordion-option="toggle">
<button id="accordion-head-1" aria-level="2" aria-expanded="false" class="accordion-btn" aria-controls="accordion-region-1">
<span>Accordion Head 1</span>
</button>
<div class="wrap-accordion-contents" id="accordion-region-1" role="region" aria-labelledby="accordion-head-1">
<div class="inner-accordion-contents">
Accordion contents 1 Accordion contents 1 Accordion contents 1 Accordion contents 1
Accordion contents 1 Accordion contents 1 Accordion contents 1 Accordion contents 1
Accordion contents 1 Accordion contents 1 Accordion contents 1 Accordion contents 1
Accordion contents 1 Accordion contents 1 Accordion contents 1 Accordion contents 1
Accordion contents 1 Accordion contents 1 Accordion contents 1 Accordion contents 1
Accordion contents 1 Accordion contents 1 Accordion contents 1 Accordion contents 1
</div>
</div>
<button id="accordion-head-2" aria-level="2" aria-expanded="false" class="accordion-btn" aria-controls="accordion-region-2">
<span>Accordion Head 2</span>
</button>
<div class="wrap-accordion-contents" id="accordion-region-2" role="region" aria-labelledby="accordion-head-2">
<div class="inner-accordion-contents">
Accordion contents 2 Accordion contents 2 Accordion contents 2 Accordion contents 2
Accordion contents 2 Accordion contents 2 Accordion contents 2 Accordion contents 2
Accordion contents 2 Accordion contents 2 Accordion contents 2 Accordion contents 2
Accordion contents 2 Accordion contents 2 Accordion contents 2 Accordion contents 2
Accordion contents 2 Accordion contents...
SCSS
.wrap-accordion-group {
max-width: 500px;
float: left;
margin-right: 30px;
}
.accordion-btn {
position: relative;
z-index: 0;
width: 100%;
height: 40px;
padding: 0 10px;
border: 1px solid #ccc;
background-color: #fff;
text-align: left;
font-size: 16px;
cursor: pointer;
&::after {
display: block;
content: '';
position: absolute;
top: 45%;
right: 10px;
width: 10px;
height: 10px;
box-sizing: border-box;
border-left: 1px solid #000;
border-bottom: 1px solid #000;
transform: rotate(-45deg) translateY(-50%);
transform-origin: left center;
transition: transform .5s;
}
&[aria-expanded="true"]::after {
top: 30%;
transform: rotate(135deg) translateY(-50%);
}
}
.wrap-accordion-contents {
height: 0;
overflow: hidden;
box-sizing: border-box;
transition: height .3s;
}
.inner-accordion-contents {
padding: 10px;
}
JavaScript
function AccordionScript() {
const _$this = this;
let accordionGroups;
_$this.init = {
// 여러 개의 accordion 을 각각 독립적으로 이벤트 실행
getAccordionGroups: () => {
// 현재 페이지에 있는 모든 accordion 을 배열로 담음
accordionGroups = document.querySelectorAll('[data-role="accordion-group"]');
accordionGroups.forEach(function(accordionGroup) {
_$this.init.getAccordionBtns(accordionGroup);
});
},
// accordion 버튼 클릭 이벤트를 독립적으로 실행
getAccordionBtns: (accordionGroup) => {
// 배열에 담긴 accordion 내부 버튼을 찾아서
const accordionBtns = accordionGroup.querySelectorAll('.accordion-btn');
accordionBtns.forEach(function(accordionBtn) {
// 클릭 이벤트를 실행
_$this.clickAction.accordionBtnClick(accordionBtn);
accordionBtn.nextElementSibling.style.transitionDuration = accordionBtn.nextElementSibling.scrollHeight * 0.0016 + 's';
// 초기 셋팅 : button 의 aria-expanded 값이 false 인 accordion contents 에 hidden 값 넣기
if (accordionBtn.ariaExpanded === 'false' && accordionBtn.nextElementSibling !== null) accordionBtn.nextElementSibling.setAttribute('hidden', 'true');
// 초기 셋팅 : button 의 aria-expanded 값이 true 인 accordion contents 에 height size 넣기
if (accordionBtn.ariaExpanded === 'true' && accordionBtn.nextElementSibling !== null) accordionBtn.nextElementSibling.style.height = accordionBtn.nextElementSibling.scrollHeight + 'px';
});
},
};
_$this.accordionEvent = {
removeEvent: (target, accordionGroup) => {
const accordionBtns = accordionGroup.querySelectorAll('.accordion-btn');
const accordionContents = accordionGroup.querySelectorAll('[role="region"]');
for (let accordionBtn of...