JSFiddle - React, Tailwind, and code Playground
by aka_SKIff
HTML
<div class="item__extra" data-accordion>
<div class="accordion__item collapsible-opened" data-collapsible data-collapsible-type="accordion">
<div class="accordion__trigger" data-collapsible-trigger>Дополнительная информация</div>
<div class="accordion__body" data-collapsible-body>
<div class="accordion__inner" data-collapsible-inner>
Любой текст 1
</div>
</div>
</div>
<div class="accordion__item collapsible-closed" data-collapsible data-collapsible-type="accordion">
<div class="accordion__trigger" data-collapsible-trigger>Дополнительная информация 2</div>
<div class="accordion__body" data-collapsible-body>
<div class="accordion__inner" data-collapsible-inner>
Любой текст 2
</div>
</div>
</div>
</div>
SCSS
.collapsible-closed {
[data-collapsible-body] {
height: 0!important;
}
}
[data-collapsible-body] {
overflow: hidden;
transition: height 0.3s;
}
[data-collapsible] {}
[data-collapsible-header] {}
[data-collapsible-inner] {}
.accordion {}
.accordion__item {}
.accordion__trigger {
line-height: 20px;
font-size: 16px;
color: #231F20;
display: inline-block;
position: relative;
padding-left: 16px;
overflow: hidden;
&:hover {
cursor: pointer;
}
&:before {
/*vertical*/
content: '';
position: absolute;
width: 1px;
height: 9px;
background: black;
left: 4px;
top: 5px;
transform-origin: 50% 50%;
transition: transform 0.3s;
}
&:after {
/*horizontal*/
content: '';
position: absolute;
width: 9px;
height: 1px;
background: black;
left: 0;
top: 50%;
margin-top: -1px;
}
.collapsible-opened & {
&:before {
transform: rotate(90deg);
}
}
}
.accordion__body {}
.accordion__inner {
padding-top: 1rem;
padding-bottom: 1rem;
}
Babel + JSX
function closest(el, selector) {
const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
while (el) {
if (matchesSelector.call(el, selector)) {
break;
}
el = el.parentElement;
}
return el;
}
class Accordion {
constructor() {
this.events = {
handleCollapsibleTriggerClick: (e) => {
e.preventDefault();
const _this = e.target;
const _collapsible = closest(_this, '[data-collapsible]');
const _collapsibleType = _collapsible.getAttribute('data-collapsible-type');
const _accordion = (_collapsibleType === 'accordion') ? closest(_this, '[data-accordion]') : null;
const _collapsibleOpened = _accordion ? _accordion.querySelector('.collapsible-opened') : null;
if (_collapsible.classList.contains('collapsible-opened') && !_accordion) {
_collapsible.classList.remove('collapsible-opened');
_collapsible.classList.add('collapsible-closed');
} else {
if (_accordion) {
_collapsibleOpened.classList.remove('collapsible-opened');
_collapsibleOpened.classList.add('collapsible-closed');
}
_collapsible.classList.add('collapsible-opened');
_collapsible.classList.remove('collapsible-closed');
}
}
};
this.collapsibles = Array.prototype.slice.call(document.querySelectorAll('[data-collapsible]'));
this.initialize();
}
getFullHeight(el) {
let height = el.offsetHeight;
const style = getComputedStyle(el);
height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
return height;
}
initialize() {
this.collapsibles.forEach((elem) => {
const _body = elem.querySelector('[data-collapsible-body]');
const _inner = elem.querySelector('[data-collapsible-inner]');
_body.style.height = this.getFullHeight(_inner) + 'px';
...