Tab
같은 맥락의 콘텐츠를 뷰 단위로 전환합니다. 페이지 수준은 Underline, 카드 안의 보조 전환은 Pill.
1. Default
밑줄 스타일의 기본 탭입니다.
HTML
<div class="tabs" role="tablist">
<button type="button" class="tab on" role="tab" aria-selected="true">개요</button>
<button type="button" class="tab" role="tab" aria-selected="false">이벤트</button>
<button type="button" class="tab" role="tab" aria-selected="false">정책</button>
</div>CSS · .tabs, .tab-panel
/* JS Design System v0.6 · .tabs, .tab-panel · 토큰(var(--*))은 assets/style.css :root 참고 */
.tabs{display:flex;gap:24px;border-bottom:1px solid var(--border-default);width:100%}
.tabs .tab{display:inline-flex;align-items:center;padding:10px 2px;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;font:inherit;font-size:14px;font-weight:500;color:var(--text-tertiary);cursor:pointer;white-space:nowrap;transition:color var(--motion-fast)}
.tabs .tab:hover{color:var(--text-primary)}
.tabs .tab.on{color:var(--text-primary);font-weight:700;border-bottom-color:var(--text-primary)}
.tabs .tab[disabled]{opacity:.4;cursor:not-allowed}
.tabs .tab .count{font-size:12px;font-weight:700;padding:1px 6px;border-radius:var(--radius-full);background:var(--bg-panel);color:var(--text-secondary);min-width:0;height:auto}
.tabs .tab.on .count{background:var(--accent-subtle);color:var(--accent-text)}
.tabs.accent .tab.on{color:var(--accent-text);border-bottom-color:var(--accent-graphic)}
.tabs.pill{display:inline-flex;gap:4px;border:0;background:var(--bg-panel);padding:3px;border-radius:var(--radius-md);width:auto}
.tabs.pill .tab{padding:6px 14px;border:0;border-radius:6px;margin:0;font-size:14px}
.tabs.pill .tab.on{background:var(--bg-surface);box-shadow:var(--shadow-1);font-weight:600}
.tabs.sm .tab{font-size:12px;padding:8px 12px}
.tab-panel{padding:20px 0;font-size:14px;color:var(--text-secondary)}React · @jiran/ds-react
import { Tab, TabList, Tabs } from "@jiran/ds-react";
export default function Example() {
return (
<Tabs defaultValue="overview">
<TabList>
<Tab value="overview">개요</Tab>
<Tab value="events">이벤트</Tab>
<Tab value="policy">정책</Tab>
</TabList>
</Tabs>
);
}2. Underline
기본. role=tablist / tab / aria-selected. 활성은 .on.
선택한 탭의 내용이 여기에 표시됩니다.
HTML
<div style="width:100%;max-width:640px">
<div class="tabs" role="tablist">
<button type="button" class="tab on" role="tab" aria-selected="true">개요</button>
<button type="button" class="tab" role="tab" aria-selected="false">이벤트</button>
<button type="button" class="tab" role="tab" aria-selected="false">정책</button>
<button type="button" class="tab" role="tab" aria-selected="false" disabled>리포트</button>
</div>
<div class="tab-panel" role="tabpanel">선택한 탭의 내용이 여기에 표시됩니다.</div>
</div>CSS · .tabs, .tab-panel
/* JS Design System v0.6 · .tabs, .tab-panel · 토큰(var(--*))은 assets/style.css :root 참고 */
.tabs{display:flex;gap:24px;border-bottom:1px solid var(--border-default);width:100%}
.tabs .tab{display:inline-flex;align-items:center;padding:10px 2px;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;font:inherit;font-size:14px;font-weight:500;color:var(--text-tertiary);cursor:pointer;white-space:nowrap;transition:color var(--motion-fast)}
.tabs .tab:hover{color:var(--text-primary)}
.tabs .tab.on{color:var(--text-primary);font-weight:700;border-bottom-color:var(--text-primary)}
.tabs .tab[disabled]{opacity:.4;cursor:not-allowed}
.tabs .tab .count{font-size:12px;font-weight:700;padding:1px 6px;border-radius:var(--radius-full);background:var(--bg-panel);color:var(--text-secondary);min-width:0;height:auto}
.tabs .tab.on .count{background:var(--accent-subtle);color:var(--accent-text)}
.tabs.accent .tab.on{color:var(--accent-text);border-bottom-color:var(--accent-graphic)}
.tabs.pill{display:inline-flex;gap:4px;border:0;background:var(--bg-panel);padding:3px;border-radius:var(--radius-md);width:auto}
.tabs.pill .tab{padding:6px 14px;border:0;border-radius:6px;margin:0;font-size:14px}
.tabs.pill .tab.on{background:var(--bg-surface);box-shadow:var(--shadow-1);font-weight:600}
.tabs.sm .tab{font-size:12px;padding:8px 12px}
.tab-panel{padding:20px 0;font-size:14px;color:var(--text-secondary)}React · @jiran/ds-react
import { Tab, TabList, TabPanel, Tabs } from "@jiran/ds-react";
export default function Example() {
return (
<div style={{ width: "100%", maxWidth: 640 }}>
<Tabs defaultValue="overview">
<TabList>
<Tab value="overview">개요</Tab>
<Tab value="events">이벤트</Tab>
<Tab value="policy">정책</Tab>
<Tab value="report" disabled>리포트</Tab>
</TabList>
<TabPanel value="overview">선택한 탭의 내용이 여기에 표시됩니다.</TabPanel>
<TabPanel value="events">이벤트 목록</TabPanel>
<TabPanel value="policy">정책 목록</TabPanel>
</Tabs>
</div>
);
}3. With Count
탭마다 건수를 보여줄 때 .count.
HTML
<div class="tabs" role="tablist" style="max-width:640px">
<button type="button" class="tab on" role="tab" aria-selected="true">전체<span class="count">128</span></button>
<button type="button" class="tab" role="tab" aria-selected="false">차단<span class="count">37</span></button>
<button type="button" class="tab" role="tab" aria-selected="false">검토 필요<span class="count">5</span></button>
</div>CSS · .tabs, .tab-panel
/* JS Design System v0.6 · .tabs, .tab-panel · 토큰(var(--*))은 assets/style.css :root 참고 */
.tabs{display:flex;gap:24px;border-bottom:1px solid var(--border-default);width:100%}
.tabs .tab{display:inline-flex;align-items:center;padding:10px 2px;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;font:inherit;font-size:14px;font-weight:500;color:var(--text-tertiary);cursor:pointer;white-space:nowrap;transition:color var(--motion-fast)}
.tabs .tab:hover{color:var(--text-primary)}
.tabs .tab.on{color:var(--text-primary);font-weight:700;border-bottom-color:var(--text-primary)}
.tabs .tab[disabled]{opacity:.4;cursor:not-allowed}
.tabs .tab .count{font-size:12px;font-weight:700;padding:1px 6px;border-radius:var(--radius-full);background:var(--bg-panel);color:var(--text-secondary);min-width:0;height:auto}
.tabs .tab.on .count{background:var(--accent-subtle);color:var(--accent-text)}
.tabs.accent .tab.on{color:var(--accent-text);border-bottom-color:var(--accent-graphic)}
.tabs.pill{display:inline-flex;gap:4px;border:0;background:var(--bg-panel);padding:3px;border-radius:var(--radius-md);width:auto}
.tabs.pill .tab{padding:6px 14px;border:0;border-radius:6px;margin:0;font-size:14px}
.tabs.pill .tab.on{background:var(--bg-surface);box-shadow:var(--shadow-1);font-weight:600}
.tabs.sm .tab{font-size:12px;padding:8px 12px}
.tab-panel{padding:20px 0;font-size:14px;color:var(--text-secondary)}React · @jiran/ds-react
import { Tab, TabList, Tabs } from "@jiran/ds-react";
export default function Example() {
return (
<Tabs defaultValue="all">
<TabList style={{ maxWidth: 640 }}>
<Tab value="all" count={128}>전체</Tab>
<Tab value="blocked" count={37}>차단</Tab>
<Tab value="review" count={5}>검토 필요</Tab>
</TabList>
</Tabs>
);
}4. Pill
카드·패널 안의 보조 전환. 폭은 내용에 맞춤.
HTML
<div class="tabs pill" role="tablist">
<button type="button" class="tab on" role="tab" aria-selected="true">일간</button>
<button type="button" class="tab" role="tab" aria-selected="false">주간</button>
<button type="button" class="tab" role="tab" aria-selected="false">월간</button>
</div>CSS · .tabs, .tab-panel
/* JS Design System v0.6 · .tabs, .tab-panel · 토큰(var(--*))은 assets/style.css :root 참고 */
.tabs{display:flex;gap:24px;border-bottom:1px solid var(--border-default);width:100%}
.tabs .tab{display:inline-flex;align-items:center;padding:10px 2px;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;font:inherit;font-size:14px;font-weight:500;color:var(--text-tertiary);cursor:pointer;white-space:nowrap;transition:color var(--motion-fast)}
.tabs .tab:hover{color:var(--text-primary)}
.tabs .tab.on{color:var(--text-primary);font-weight:700;border-bottom-color:var(--text-primary)}
.tabs .tab[disabled]{opacity:.4;cursor:not-allowed}
.tabs .tab .count{font-size:12px;font-weight:700;padding:1px 6px;border-radius:var(--radius-full);background:var(--bg-panel);color:var(--text-secondary);min-width:0;height:auto}
.tabs .tab.on .count{background:var(--accent-subtle);color:var(--accent-text)}
.tabs.accent .tab.on{color:var(--accent-text);border-bottom-color:var(--accent-graphic)}
.tabs.pill{display:inline-flex;gap:4px;border:0;background:var(--bg-panel);padding:3px;border-radius:var(--radius-md);width:auto}
.tabs.pill .tab{padding:6px 14px;border:0;border-radius:6px;margin:0;font-size:14px}
.tabs.pill .tab.on{background:var(--bg-surface);box-shadow:var(--shadow-1);font-weight:600}
.tabs.sm .tab{font-size:12px;padding:8px 12px}
.tab-panel{padding:20px 0;font-size:14px;color:var(--text-secondary)}React · @jiran/ds-react
import { Tab, TabList, Tabs } from "@jiran/ds-react";
export default function Example() {
return (
<Tabs defaultValue="day">
<TabList pill>
<Tab value="day">일간</Tab>
<Tab value="week">주간</Tab>
<Tab value="month">월간</Tab>
</TabList>
</Tabs>
);
}5. Small / Accent
밀도 높은 패널은 .sm, 제품 컬러 강조는 .accent.
HTML
<div class="tabs sm accent" role="tablist" style="max-width:480px">
<button type="button" class="tab on" role="tab" aria-selected="true">상세</button>
<button type="button" class="tab" role="tab" aria-selected="false">타임라인</button>
<button type="button" class="tab" role="tab" aria-selected="false">관련 이벤트</button>
</div>CSS · .tabs, .tab-panel
/* JS Design System v0.6 · .tabs, .tab-panel · 토큰(var(--*))은 assets/style.css :root 참고 */
.tabs{display:flex;gap:24px;border-bottom:1px solid var(--border-default);width:100%}
.tabs .tab{display:inline-flex;align-items:center;padding:10px 2px;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;font:inherit;font-size:14px;font-weight:500;color:var(--text-tertiary);cursor:pointer;white-space:nowrap;transition:color var(--motion-fast)}
.tabs .tab:hover{color:var(--text-primary)}
.tabs .tab.on{color:var(--text-primary);font-weight:700;border-bottom-color:var(--text-primary)}
.tabs .tab[disabled]{opacity:.4;cursor:not-allowed}
.tabs .tab .count{font-size:12px;font-weight:700;padding:1px 6px;border-radius:var(--radius-full);background:var(--bg-panel);color:var(--text-secondary);min-width:0;height:auto}
.tabs .tab.on .count{background:var(--accent-subtle);color:var(--accent-text)}
.tabs.accent .tab.on{color:var(--accent-text);border-bottom-color:var(--accent-graphic)}
.tabs.pill{display:inline-flex;gap:4px;border:0;background:var(--bg-panel);padding:3px;border-radius:var(--radius-md);width:auto}
.tabs.pill .tab{padding:6px 14px;border:0;border-radius:6px;margin:0;font-size:14px}
.tabs.pill .tab.on{background:var(--bg-surface);box-shadow:var(--shadow-1);font-weight:600}
.tabs.sm .tab{font-size:12px;padding:8px 12px}
.tab-panel{padding:20px 0;font-size:14px;color:var(--text-secondary)}React · @jiran/ds-react
import { Tab, TabList, Tabs } from "@jiran/ds-react";
export default function Example() {
return (
<Tabs defaultValue="detail">
<TabList sm accent style={{ maxWidth: 480 }}>
<Tab value="detail">상세</Tab>
<Tab value="timeline">타임라인</Tab>
<Tab value="related">관련 이벤트</Tab>
</TabList>
</Tabs>
);
}Props
HTML 에서는 클래스와 속성으로, React(@jiran/ds-react)에서는 같은 이름의 prop(variant · size …)으로 변형·상태를 지정합니다.
| Prop / Class | Type · Values | Default | Description |
|---|---|---|---|
| .tabs | container | — | role=tablist. 기본 Underline, 전체 폭 |
| .tab | button | — | role=tab, aria-selected. 활성 .on |
| .pill | boolean | false | 캡슐형(보조 전환) |
| .sm / .accent | boolean | false | 작은 크기 / 활성 색 accent |
| .count | element | — | 건수 배지 |
| disabled | attribute | — | 비활성 탭 |
Usage
React: @jiran/ds-react 패키지를 설치하고 style.css 를 한 번 import 하면 위 React 탭 코드를 그대로 쓸 수 있습니다(React Package). HTML: assets/style.css 를 연결하고(일부만 필요하면 아래 컴포넌트 CSS 복사), 동작이 필요하면 assets/ds.js 를 함께 넣습니다 — 이 페이지의 프리뷰가 그 스크립트로 동작합니다. 색은 전부 토큰(var(--accent) 등)을 참조하므로 --accent-* 만 제품 컬러로 바꾸면 됩니다.
React @jiran/ds-react
npm i @jiran/ds-react
// main.tsx — 앱 진입점에서 한 번
import "@jiran/ds-react/style.css";
// 컴포넌트
import { Tabs, TabList, Tab, TabPanel } from "@jiran/ds-react";HTML
<!-- 1) 토큰 + 전체 컴포넌트 스타일 한 번에 연결 -->
<link rel="stylesheet" href="assets/style.css">
<!-- 동작(드롭다운·탭·달력·표 정렬/선택·토스트 등) — 순수 JS 한 파일. React 제품은 불필요 -->
<script src="assets/ds.js" defer></script>
<!-- 2) 또는 아래 "Component CSS" 만 프로젝트 CSS 에 붙이고,
:root 토큰은 Foundations › Design Token 에서 복사 -->Component CSS .tabs, .tab-panel
/* JS Design System v0.6 · .tabs, .tab-panel · 토큰(var(--*))은 assets/style.css :root 참고 */
.tabs{display:flex;gap:24px;border-bottom:1px solid var(--border-default);width:100%}
.tabs .tab{display:inline-flex;align-items:center;padding:10px 2px;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;font:inherit;font-size:14px;font-weight:500;color:var(--text-tertiary);cursor:pointer;white-space:nowrap;transition:color var(--motion-fast)}
.tabs .tab:hover{color:var(--text-primary)}
.tabs .tab.on{color:var(--text-primary);font-weight:700;border-bottom-color:var(--text-primary)}
.tabs .tab[disabled]{opacity:.4;cursor:not-allowed}
.tabs .tab .count{font-size:12px;font-weight:700;padding:1px 6px;border-radius:var(--radius-full);background:var(--bg-panel);color:var(--text-secondary);min-width:0;height:auto}
.tabs .tab.on .count{background:var(--accent-subtle);color:var(--accent-text)}
.tabs.accent .tab.on{color:var(--accent-text);border-bottom-color:var(--accent-graphic)}
.tabs.pill{display:inline-flex;gap:4px;border:0;background:var(--bg-panel);padding:3px;border-radius:var(--radius-md);width:auto}
.tabs.pill .tab{padding:6px 14px;border:0;border-radius:6px;margin:0;font-size:14px}
.tabs.pill .tab.on{background:var(--bg-surface);box-shadow:var(--shadow-1);font-weight:600}
.tabs.sm .tab{font-size:12px;padding:8px 12px}
.tab-panel{padding:20px 0;font-size:14px;color:var(--text-secondary)}