JSFiddle - React, Tailwind, and code Playground

by TheCrossCarrier

HTML

<!-- Copy this structure and edit class names   -->
  <div class="block">
    <div class="block__spoiler"> Click me</div>

    <div class="block__content">
      Content
    </div>
  </div>
<!------------------------------------------------>

CSS

/* Don't forget to edit class names (except .spoiler_opened) */
.block {
  overflow: hidden;
  transition: height 0.5s ease;
}

.block__spoiler {
  position: relative;
  width: fit-content;
  cursor: pointer;
}

.block__spoiler::before {
  content: "➤";
  position: absolute;
  right: -1.1em;
  transform: rotate(180deg);
  transition: transform 0.5s ease;
}

.spoiler_opened.block__spoiler::before {
  transform: rotate(90deg);
}

.block__content {
  display: none;
}

JavaScript

Spoiler('block', 'block__spoiler', 'block__content', 'flex')

function Spoiler(blockClass, buttonClass, contentClass,
  contentDisplayType = 'block') {
  
  document.addEventListener('DOMContentLoaded', () => {
    'use strict'

    const
      block = document.querySelector(`.${blockClass}`),
      button = document.querySelector(`.${buttonClass}`),
      content = document.querySelector(`.${contentClass}`) 

    const blockInitialHeight = window.getComputedStyle(block, null)
      .getPropertyValue('height')

    // if block height: 'min-content' etc.
    block.style.height = blockInitialHeight

    let transitionEnd = () => {
      block.removeEventListener('transitionend', transitionEnd)
      content.style.display = 'none'
    }

    button.onclick = () => {
      if (button.classList.contains('spoiler_opened')) {
        block.style.height = blockInitialHeight
        block.addEventListener('transitionend', transitionEnd)
      }
      else {
        block.removeEventListener('transitionend', transitionEnd)
        content.style.display = contentDisplayType
        block.style.height = block.scrollHeight + 'px'
      }

      button.classList.toggle('spoiler_opened')
    }
  })
}