Lompat ke konten

Tab

Untuk membelah satu objek menjadi beberapa tampilan, saat hanya satu yang perlu terlihat sekaligus.

Navigasi

Pratinjau langsung

Sumber

<div class="dc-tabs">
  <input class="dc-tabs__radio" type="radio" name="dc-tab" id="dc-tab-1" checked>
  <input class="dc-tabs__radio" type="radio" name="dc-tab" id="dc-tab-2">
  <input class="dc-tabs__radio" type="radio" name="dc-tab" id="dc-tab-3">
  <nav class="dc-tabs__bar" aria-label="템플릿 정보">
    <label class="dc-tabs__tab" for="dc-tab-1">개요</label>
    <label class="dc-tabs__tab" for="dc-tab-2">사용법</label>
    <label class="dc-tabs__tab" for="dc-tab-3">리뷰 <span class="dc-tabs__count">12</span></label>
  </nav>
  <div class="dc-tabs__panel"><p>표지부터 마무리까지 12장. 16:9 와 4:3 두 벌이 함께 들어 있고, 웹폰트 없이 시스템 글꼴만 씁니다.</p></div>
  <div class="dc-tabs__panel"><p>도형은 그대로 두고 글자만 바꾸면 여백이 흐트러지지 않습니다. 색은 마스터 슬라이드의 테마색 두 개만 바꾸면 전체에 퍼집니다.</p></div>
  <div class="dc-tabs__panel"><p>투자 심사 발표에 그대로 썼습니다. 표 서식을 다시 만들지 않아 이틀은 벌었어요. — 홍길동</p></div>
</div>
.dc-tabs { position: relative; font-family: var(--dc-font); }
.dc-tabs__radio {
  position: absolute; top: 0; left: 0;
  width: 1px; height: 1px; margin: 0; opacity: 0;
  pointer-events: none;
}
.dc-tabs__bar {
  display: flex; gap: var(--dc-1);
  border-bottom: 1px solid var(--dc-line);
  overflow-x: auto; scrollbar-width: thin;
}
.dc-tabs__tab {
  display: flex; align-items: center; gap: var(--dc-2);
  min-height: 44px; padding: 0 var(--dc-3);
  margin-bottom: -1px; border-bottom: 2px solid transparent;
  color: var(--dc-text-sub); font-size: 14px; font-weight: 600;
  white-space: nowrap; cursor: pointer;
  transition: color var(--dc-fast), border-color var(--dc-fast);
}
.dc-tabs__tab:hover { color: var(--dc-text); }
.dc-tabs__count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--dc-r-full);
  background: var(--dc-sunken); color: var(--dc-text-sub);
  font-size: 12px; font-weight: 700;
}
.dc-tabs__panel {
  display: none; padding: var(--dc-4) var(--dc-3);
  color: var(--dc-text); font-size: 14px; line-height: 1.65;
}
.dc-tabs__panel p { margin: 0; }

.dc-tabs--pill .dc-tabs__bar {
  gap: var(--dc-1); padding: var(--dc-1);
  border-bottom: 0; border-radius: var(--dc-r-full);
  background: var(--dc-sunken);
}
.dc-tabs--pill .dc-tabs__tab {
  min-height: 40px; padding: 0 var(--dc-4);
  margin-bottom: 0; border-bottom: 0; border-radius: var(--dc-r-full);
}
.dc-tabs--scroll .dc-tabs__bar { flex-wrap: nowrap; scroll-snap-type: x proximity; }
.dc-tabs--scroll .dc-tabs__tab { scroll-snap-align: start; }

.dc-tabs__radio:nth-of-type(1):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(1) {
  color: var(--dc-brand-text); border-bottom-color: var(--dc-brand);
}
.dc-tabs__radio:nth-of-type(1):focus-visible ~ .dc-tabs__bar .dc-tabs__tab:nth-child(1) {
  outline: 2px solid var(--dc-brand); outline-offset: 2px; border-radius: var(--dc-r-xs);
}
.dc-tabs__radio:nth-of-type(1):checked ~ .dc-tabs__panel:nth-of-type(1) { display: block; }
.dc-tabs--pill .dc-tabs__radio:nth-of-type(1):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(1) {
  background: var(--dc-surface); color: var(--dc-brand-text); box-shadow: var(--dc-sh-1);
}
.dc-tabs__radio:nth-of-type(2):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(2) {
  color: var(--dc-brand-text); border-bottom-color: var(--dc-brand);
}
.dc-tabs__radio:nth-of-type(2):focus-visible ~ .dc-tabs__bar .dc-tabs__tab:nth-child(2) {
  outline: 2px solid var(--dc-brand); outline-offset: 2px; border-radius: var(--dc-r-xs);
}
.dc-tabs__radio:nth-of-type(2):checked ~ .dc-tabs__panel:nth-of-type(2) { display: block; }
.dc-tabs--pill .dc-tabs__radio:nth-of-type(2):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(2) {
  background: var(--dc-surface); color: var(--dc-brand-text); box-shadow: var(--dc-sh-1);
}
.dc-tabs__radio:nth-of-type(3):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(3) {
  color: var(--dc-brand-text); border-bottom-color: var(--dc-brand);
}
.dc-tabs__radio:nth-of-type(3):focus-visible ~ .dc-tabs__bar .dc-tabs__tab:nth-child(3) {
  outline: 2px solid var(--dc-brand); outline-offset: 2px; border-radius: var(--dc-r-xs);
}
.dc-tabs__radio:nth-of-type(3):checked ~ .dc-tabs__panel:nth-of-type(3) { display: block; }
.dc-tabs--pill .dc-tabs__radio:nth-of-type(3):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(3) {
  background: var(--dc-surface); color: var(--dc-brand-text); box-shadow: var(--dc-sh-1);
}
.dc-tabs__radio:nth-of-type(4):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(4) {
  color: var(--dc-brand-text); border-bottom-color: var(--dc-brand);
}
.dc-tabs__radio:nth-of-type(4):focus-visible ~ .dc-tabs__bar .dc-tabs__tab:nth-child(4) {
  outline: 2px solid var(--dc-brand); outline-offset: 2px; border-radius: var(--dc-r-xs);
}
.dc-tabs__radio:nth-of-type(4):checked ~ .dc-tabs__panel:nth-of-type(4) { display: block; }
.dc-tabs--pill .dc-tabs__radio:nth-of-type(4):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(4) {
  background: var(--dc-surface); color: var(--dc-brand-text); box-shadow: var(--dc-sh-1);
}
.dc-tabs__radio:nth-of-type(5):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(5) {
  color: var(--dc-brand-text); border-bottom-color: var(--dc-brand);
}
.dc-tabs__radio:nth-of-type(5):focus-visible ~ .dc-tabs__bar .dc-tabs__tab:nth-child(5) {
  outline: 2px solid var(--dc-brand); outline-offset: 2px; border-radius: var(--dc-r-xs);
}
.dc-tabs__radio:nth-of-type(5):checked ~ .dc-tabs__panel:nth-of-type(5) { display: block; }
.dc-tabs--pill .dc-tabs__radio:nth-of-type(5):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(5) {
  background: var(--dc-surface); color: var(--dc-brand-text); box-shadow: var(--dc-sh-1);
}
.dc-tabs__radio:nth-of-type(6):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(6) {
  color: var(--dc-brand-text); border-bottom-color: var(--dc-brand);
}
.dc-tabs__radio:nth-of-type(6):focus-visible ~ .dc-tabs__bar .dc-tabs__tab:nth-child(6) {
  outline: 2px solid var(--dc-brand); outline-offset: 2px; border-radius: var(--dc-r-xs);
}
.dc-tabs__radio:nth-of-type(6):checked ~ .dc-tabs__panel:nth-of-type(6) { display: block; }
.dc-tabs--pill .dc-tabs__radio:nth-of-type(6):checked ~ .dc-tabs__bar .dc-tabs__tab:nth-child(6) {
  background: var(--dc-surface); color: var(--dc-brand-text); box-shadow: var(--dc-sh-1);
}

Cara memakainya

  • Tab bukan filter — pakai untuk sisi berbeda dari objek yang sama
  • Label satu sampai dua kata; label yang turun baris tak lagi terbaca sebagai tab
  • Lebih dari lima tab, pakai varian gulir; lebih dari sepuluh, pindah ke sidebar

Hal yang perlu diwaspadai

  • Versi radio tidak butuh skrip tapi tak punya makna role="tablist" — tambahkan ARIA lewat JS kalau semantik tab sungguhan dibutuhkan
  • Jangan tandai tab aktif hanya dengan warna; ubah juga garis bawah atau ketebalannya

Berikutnya