Tab
관련된 화면 구획을 자동 활성화 키보드 탐색과 연결해 같은 문맥 안에서 전환합니다.
예제
Tab 자동 활성화, 균등 배치, native scroll
Arrow·Home·End 탐색, disabled skip, controlled selection, overflow와 긴 문자열을 확인하세요.
주문 요약 패널
결제 내역 패널
영수증 패널
주문 설정 패널
사용해야 할 때
같은 정보 구조 안에서 요약·내역·설정처럼 서로 관련된 패널을 즉시 비교하거나 전환할 때 사용합니다. 현재 선택을 유지한 채 페이지 이동 없이 패널만 바뀌는 문맥에 적합합니다.
사용하지 말아야 할 때
선택이 URL과 브라우저 history를 바꿔야 한다면 navigation link를 사용합니다. 세로 orientation, notification dot, manual activation, route 통합을 임의로 추가하지 않습니다. 사용자가 동시에 비교해야 하는 form 선택지는 RadioGroup을 사용합니다.
구조
root div 안에 이름이 있는 horizontal tablist, native button tab, 각 button과 ID로 연결된 tabpanel이 있습니다. 모든 panel은 관계를 유지한 채 selected panel만 표시됩니다. label과 content는 item 데이터가 소유합니다.
크기와 변형
small은 44px, 기본 large는 52px 높이입니다. 기본 equal은 두 개에서 네 개 tab을 동일한 너비로 배치하며 다섯 개 이상은 문서화된 misuse입니다. scroll은 content width와 native horizontal scroll, 오른쪽 edge affordance를 사용합니다.
상태와 동작
기본값은 첫 enabled item입니다. value와 onValueChange로 controlled, defaultValue로 uncontrolled selection을 구성합니다. Left·Right Arrow는 enabled tab 사이를 순환하며 focus와 selection을 함께 옮깁니다. Home과 End도 첫째·마지막 enabled tab을 자동 선택합니다. manual activation mode는 제공하지 않습니다.
반응형 동작
equal label은 좁은 container와 text zoom에서 줄바꿈되고 scroll은 page가 아니라 tablist만 가로로 scroll됩니다. 긴 unbroken label과 panel content도 component 경계를 넘지 않습니다. 문서 specimen은 넓은 화면에서 두 열, mobile에서 한 열입니다.
접근성
ariaLabel이 tablist의 accessible name을 제공합니다. 안정적인 ID가 aria-controls와 aria-labelledby를 연결합니다. roving tabindex로 selected tab만 tabIndex=0이며 disabled tab은 pointer와 keyboard 대상에서 제외됩니다. panel로 focus를 강제로 이동하지 않고 normal·forced-colors에서 focus와 selected indicator를 보존합니다.
React 예제
import { useState } from 'react';
import { Tab, type TabItem } from '@hds/react';
import '@hds/react/styles.css';
const items = [
{ value: 'summary', label: '요약', content: <OrderSummary /> },
{ value: 'history', label: '내역', content: <OrderHistory /> },
{ value: 'receipt', label: '영수증', content: <Receipt />, disabled: true },
] satisfies readonly TabItem[];
export function OrderTabs() {
const [value, setValue] = useState('summary');
return (
<Tab
ariaLabel="주문 정보"
items={items}
value={value}
onValueChange={setValue}
/>
);
}
API
| Prop | Type | Default | 설명 |
|---|---|---|---|
ariaLabel |
string |
required | tablist의 localizable accessible name |
items |
readonly TabItem[] |
required | unique non-empty value, label, content, optional disabled |
value |
string |
- | controlled enabled value |
defaultValue |
string |
first enabled | uncontrolled 초기 enabled value |
onValueChange |
(value: string) => void |
- | pointer·keyboard automatic selection callback |
size |
'small' | 'large' |
'large' |
44px 또는 52px tab 높이 |
layout |
'equal' | 'scroll' |
'equal' |
동일 너비 또는 content-width native scroll |
| native props | Omit<HTMLAttributes<HTMLDivElement>, ‘children’ | ‘defaultValue’ | ‘onChange’> |
- | root data·aria props와 ref; style은 외부 배치 whitelist만 보존, owned geometry/state와 dangerous HTML은 무시 |
사용 토큰
size/control/small,space/0,space/2,space/8,space/16,space/24,radius/none,radius/smfont/family/sans,font/size/body-sm,font/size/body,font/weight/semibold,font/line-height/body-sm,font/line-height/bodymotion/duration/fast,motion/easing/standard,color/bg/surface,color/text/*,color/border/default,color/action/*,color/focus/ring
Figma
Live Tab component set은 Size Small/Large × Layout Equal/Scroll × Selection First/Second/Third = 12 variants와 First label, Second label, Third label TEXT properties를 제공합니다. Equal은 세 항목을 균등 배치하고 Scroll은 320px viewport 안의 360px content와 token-bound edge affordance를 보여 줍니다. disabled와 긴 label overflow는 variant 축을 늘리지 않고 별도 문서 specimen으로 검증했습니다. 구현 방향은 TDS Mobile Tab reference와 함께 검토합니다.
지원 상태
| React | Svelte | React Native |
|---|---|---|
| preview | planned | planned |