JSFiddle - React, Tailwind, and code Playground
by seulbiLee
HTML
<link rel="stylesheet" href="https://unpkg.com/swiper@7/swiper-bundle.min.css" />
<script src="https://unpkg.com/swiper@7/swiper-bundle.min.js"></script>
<div class="wrap-slide-box">
<div class="swiper-button-next"></div>
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide slide01" tabindex="-1">
<h1>slide 1</h1>
<ol>
<li><a href="javascript:;">링크 1-1</a></li>
<li><a href="javascript:;">링크 1-2</a></li>
<li><a href="javascript:;">링크 1-3</a></li>
<li><a href="javascript:;">링크 1-4</a></li>
</ol>
</div>
<div class="swiper-slide slide02" tabindex="-1">
<h1>slide 2</h1>
</div>
<div class="swiper-slide slide03" tabindex="-1">
<h1>slide 3</h1>
<ol>
<li><a href="javascript:;">링크 3-1</a></li>
<li><a href="javascript:;">링크 3-2</a></li>
<li><a href="javascript:;">링크 3-3</a></li>
<li><a href="javascript:;">링크 3-4</a></li>
</ol>
</div>
<div class="swiper-slide slide04" tabindex="-1">
<h1>slide 4</h1>
<ol>
<li><a href="javascript:;">링크 4-1</a></li>
<li><a href="javascript:;">링크 4-2</a></li>
<li><a href="javascript:;">링크 4-3</a></li>
<li><a href="javascript:;">링크 4-4</a></li>
</ol>
</div>
<div class="swiper-slide slide05" tabindex="-1">
<h1>slide 5</h1>
<ol>
<li><a href="javascript:;">링크 5-1</a></li>
<li><a href="javascript:;">링크 5-2</a></li>
<li><a href="javascript:;">링크 5-3</a></li>
<li><a href="javascript:;">링크 5-4</a></li>
</ol>
</div>
</div>
<div class="swiper-button-prev"></div>
<div class="swiper-pagination"></div>
</div>
</div>
CSS
.wrap-slide-box {position: relative; width: 100%; max-width: 700px; height: 400px; margin: 0 auto;}
.swiper-container {width: 80%; height: 100%; margin: 0 auto; overflow: hidden;}
.swiper-slide {display: flex; flex-wrap: wrap; align-content: center; justify-content: center; width: 100%;}
.swiper-slide h1 {width: 100%; text-align: center;}
.swiper-slide ol {width: auto; margin: 0 auto;}
.swiper-slide.slide01 {background-color: palegoldenrod;}
.swiper-slide.slide02 {background-color: paleturquoise;}
.swiper-slide.slide03 {background-color:palevioletred;}
.swiper-slide.slide04 {background-color:lightsteelblue;}
.swiper-slide.slide05 {background-color:yellowgreen;}
JavaScript
let thisSlide, // Swiper Slide
focusOut, // 슬라이드 키보드 접근 확인
slideFocus = {}, // 슬라이드 내부 탭 포커스 가능한 요소 저장
swiperWrapper = document.querySelector('.swiper-wrapper'),
slideAll, // 전체 슬라이드 저장
realSlideAll, // loop 모드 일때 복사 된 슬라이드를 제외한 실제 슬라이드 저장
slideLength, // 슬라이드 갯수 - 1
onClickNavigation, // 슬라이드 이전/다음 버튼으로 슬라이드 전환 확인
navigations = {}, // 슬라이드 이전 다음 버튼
prevEnter; // 이전 버튼 키보드 엔터로 접근 확인
const slideKeyDownEvt = (e, idx) => {
// back tab : 첫 번째 슬라이드 포커스 시
if (e.key == 'Tab' && e.shiftKey && thisSlide.realIndex === 0) {
focusOut = false;
// back tab : 그 외 슬라이드 포커스 시
} else if (e.key == 'Tab' && e.shiftKey && e.target === slideFocus[idx][0]) {
e.preventDefault();
focusOut = true;
realSlideAll[thisSlide.realIndex - 1].setAttribute('tabindex', '0');
thisSlide.slideTo(thisSlide.activeIndex - 1);
removeSlideTabindex();
} else if (e.key == 'Tab' && !e.shiftKey && e.target === slideFocus[idx][slideFocus[idx].length - 1]) {
if (idx >= slideLength) {
// tab : 마지막 슬라이드 내 마지막 요소 포커스 시
focusOut = false;
} else {
// tab : 그 외 슬라이드 내 마지막 요소 포커스 시
e.preventDefault();
if (realSlideAll[thisSlide.realIndex + 1] <= slideLength) realSlideAll[thisSlide.realIndex + 1].setAttribute('tabindex', '0');
focusOut = true;
thisSlide.slideTo(thisSlide.activeIndex + 1);
removeSlideTabindex();
};
};
};
// 슬라이드 내부 클릭 요소 tabindex 값 삭제
const removeSlideTabindex = () => {
slideAll.forEach((element, i) => {
let focusTarget = Array.prototype.slice.call(element.querySelectorAll('a, button, input, [role="button"], textarea, select, [tabindex="0"]'));
focusTarget.forEach((el, idx) => {
if (el.closest('.swiper-slide') === slideAll[thisSlide.activeIndex]) el.removeAttribute('tabindex');
});
});
};
const slideFocusAct = (e, idx, next) => {
if (onClickNavigation) {
if (e.key == 'Enter' && !next) prevEnter = true;
else if (e.key == 'Tab') {
if...