JSFiddle - React, Tailwind, and code Playground

by seulbiLee

HTML

<div class="wrap-tab-container" data-role="tab">
  <ul class="wrap-tab-list" role="tablist">
    <li class="tab-list active">
      <button id="tab-01" class="tab-button" role="tab" aria-selected="true" aria-controls="tab-panel-01">tablist 01</button>
    </li>
    <li class="tab-list">
      <button id="tab-02" class="tab-button" role="tab" aria-selected="false" aria-controls="tab-panel-02" tabindex="-1">tablist 02</button>
    </li>
    <li class="tab-list">
      <button id="tab-03" class="tab-button" role="tab" aria-selected="false" aria-controls="tab-panel-03" tabindex="-1">tablist 03</button>
    </li>
  </ul>
  <div class="wrap-tab-contents">
    <div id="tab-panel-01" class="tab-contents" role="tabpanel" aria-labelledby="tab-01" tabindex="0">
      <p>tab contents 01</p>


      <div class="wrap-tab-container" data-role="tab">
        <ul class="wrap-tab-list" role="tablist">
          <li class="tab-list active">
            <button id="tab-01-01" class="tab-button" role="tab" aria-selected="true" aria-controls="tab-panel-01-01">tablist 01</button>
          </li>
          <li class="tab-list">
            <button id="tab-02-01" class="tab-button" role="tab" aria-selected="false" aria-controls="tab-panel-02-01" tabindex="-1">tablist 02</button>
          </li>
          <li class="tab-list">
            <button id="tab-03-01" class="tab-button" role="tab" aria-selected="false" aria-controls="tab-panel-03-01" tabindex="-1">tablist 03</button>
          </li>
        </ul>
        <div class="wrap-tab-contents">
          <div id="tab-panel-01-01" class="tab-contents" role="tabpanel" aria-labelledby="tab-01-01" tabindex="0">
            <p>tab contents 01</p>
          </div>
          <div id="tab-panel-02-01" class="tab-contents" role="tabpanel" aria-labelledby="tab-02-01" tabindex="0" hidden="true">
            <p>tab contents 02</p>
          </div>
          <div id="tab-panel-03-01" class="tab-contents" role="tabpanel" aria-labelledby="tab-03-01"...

SCSS

ul, li {
  list-style: none;
  padding: 0;
  margin: 0;
}

button {cursor: pointer;}

.wrap-tab-list {
  position: relative;
  z-index: 0;
  font-size: 0;
  line-height: 0;
  .tab-list {
    & + .tab-list {
      margin-left: -1px;
    }
    &.active {
      border-color: orange;
      border-bottom: 1px solid #fff;
      z-index: 10;
      .tab-button {
        font-weight: bold;
      }
    }
    display: inline-block;
    position: relative;
    z-index: 0;
    border: 1px solid #ccc;
    border-bottom: 0;
    .tab-button {
      display: block;
      height: 40px;
      padding: 0 10px;
      font-size: 16px;
      border: 0;
      background-color: #fff;
    }
  }
}
.wrap-tab-contents {
  max-width: 500px;
  width: 100%;
  border: 1px solid orange;
  margin-top: -1px;
  .tab-contents {
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
  }
}
.wrap-tab-container {
  & + .wrap-tab-container {
    margin-top: 30px;
  }
}

JavaScript

const tabGroups = document.querySelectorAll('[data-role="tab"]');
if (tabGroups) {
  let currentTarget, targetTabWrap, targetTabListWrap, targetPanelWrap;
  // 이벤트 타겟 변수 설정
  const init = (e) => {
    currentTarget = e.target.tagName;
    currentTarget === 'BUTTON' || 'A' ? currentTarget = e.target : currentTarget = e.target.closest('button') || e.target.closest('a');
    targetTabWrap = currentTarget.closest('[data-role="tab"]');
    targetTabListWrap = targetTabWrap.querySelector('[role="tablist"]');
    targetPanelWrap = targetTabWrap.querySelector('.wrap-tab-contents');
  };
  // 클릭 이벤트
  const tabClickEvt = (e) => {
    init(e);
    if (currentTarget.ariaSelected === 'false') {
      // 미선택된 탭 속성 false 상태로 만들기
      tabRemoveEvt(targetTabListWrap, targetPanelWrap);
      // 선택 된 탭 속성 true 상태로 만들기
      tabAddEvt(currentTarget, targetTabWrap);
    };
  };
  // 키보드 접근 이벤트
  const tabKeyUpEvt = (e) => {
    init(e);
    const targetBtnWrap = currentTarget.parentElement;
    if (e.key == 'ArrowRight') {
      // 키보드 -> 화살표를 눌렀을 때
      if (targetBtnWrap.nextElementSibling) {
        targetBtnWrap.nextElementSibling.children[0].focus();
        tabRemoveEvt(targetTabListWrap, targetPanelWrap);
        tabAddEvt(targetBtnWrap.nextElementSibling.children[0], targetTabWrap);
      } 
      else homeKeyEvt(targetTabListWrap, targetTabWrap, targetPanelWrap);
    } else if (e.key == 'ArrowLeft') {
      // 키보드 <- 화살표를 눌렀을 때
      if (targetBtnWrap.previousElementSibling) {
        targetBtnWrap.previousElementSibling.children[0].focus();
        tabRemoveEvt(targetTabListWrap, targetPanelWrap);
        tabAddEvt(targetBtnWrap.previousElementSibling.children[0], targetTabWrap);
      } else endKeyEvt(targetTabListWrap, targetTabWrap, targetPanelWrap);
    } 
    // 키보드 End 키 눌렀을 때
    else if (e.key == 'End') endKeyEvt(targetTabListWrap, targetTabWrap, targetPanelWrap);
    // 키보드 Home 키 눌렀을 때
    else if (e.key == 'Home') homeKeyEvt(targetTabListWrap, targetTabWrap,...