Tabs
한 번에 하나만 보이는 패널들. 가로로도, 세로로도 놓입니다.
import { Tab, TabPanel, Tabs } from 'neba';
<Tabs defaultValue="overview">
<Tab value="overview">개요</Tab>
<Tab value="usage">사용량</Tab>
<TabPanel value="overview">오늘 배포 세 번, 전부 성공.</TabPanel>
<TabPanel value="usage">빌드 1,284분 사용.</TabPanel>
</Tabs>;<TabList> 같은 래퍼는 없습니다. 태그 사이에 쓴 것은 탭이거나 패널이고, 둘은 서로 다른 상자로 들어가야 하므로 컴포넌트가 알아서 나눕니다 — 기억해야 할 래퍼를 하나 만드는 대신에.
Props
Tabs
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| variant공통 | 'solid' | 'outline' | 'text' | 'outline' | 패널이 아니라 탭 **바**의 무게. solid는 분절 컨트롤(홈통 안의 타일), outline은 바 가장자리의 선, text는 그 선을 뺀 것 |
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 탭의 높이와 타입 스케일. Button과 같은 사다리라 툴바에 섞어 놓아도 기준선이 맞습니다 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | 의미론적 색 역할. 임의 색상값은 받지 않습니다 |
| density공통 | 'default' | 'compact' | 'default' | 여백만 바꿉니다. 높이와 글자 크기는 그대로 |
| value | string | number | null | — | 선택된 탭. controlled |
| defaultValue | string | number | null | — | 처음 선택된 탭 |
| onValueChange | (value: string | number | null) => void | — | 선택이 바뀔 때 |
| orientation공통 | 'horizontal' | 'vertical' | 'horizontal' | 바가 흐르는 방향. vertical이면 탭이 옆으로 서고 화살표 키도 그 축으로 옮겨 갑니다 |
| activateOnFocus | boolean | false | 화살표로 지나가기만 해도 선택할지. 기본이 꺼짐인 이유는 패널 하나가 데이터를 받아 온다면 탭 넷을 지나가는 것이 요청 네 번이기 때문입니다 |
| loopFocus | boolean | true | 마지막 탭에서 화살표를 누르면 처음으로 돌아갈지 |
| fullWidth | boolean | false | 탭들이 바의 폭을 똑같이 나눠 갖습니다 |
| children | ReactNode | — | Tab과 TabPanel. 둘은 알아서 나뉘어 각자의 자리에 놓이므로 감싸는 래퍼를 쓸 필요가 없습니다 |
Tab
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| value * | string | number | — | 탭의 식별자. 같은 값을 가진 TabPanel을 가리킵니다 |
| startIcon | ReactNode | — | 라벨 앞의 내용 |
| endIcon | ReactNode | — | 라벨 뒤의 내용 — 개수, Badge, 상태 점 |
| disabled | boolean | false | 사용 불가. 목록에는 남습니다 |
| children | ReactNode | — | 탭의 라벨 |
TabPanel
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| value * | string | number | — | 어느 탭이 이 패널을 보여 줄지 |
| keepMounted | boolean | false | 숨겨진 동안에도 DOM에 남깁니다. 만들기 비싼 내용이나 살아 있어야 하는 폼 상태 |
| children | ReactNode | — | 패널의 내용 |
예시
Variant
variant는 여기서 패널이 아니라 탭 바의 무게입니다.
solid— 분절 컨트롤. 바는 서리 낀 홈통이고, 표시자는 탭 사이를 미끄러지는 채워진 타일입니다.outline— 고전적인 형태. 바 가장자리의 선 위에 표시자가 올라탑니다.text— 같은 바에서 선을 뺀 것. 이미 자기 가장자리를 가진 Card 안의 탭을 위한 것입니다.
방향
세로 바는 가로 바를 돌려놓은 것이 아닙니다. Base UI가 화살표 키도 함께 다른 축으로 옮겨 주는데, 그것이 세로 탭 바를 애초에 닿을 수 있게 만드는 부분입니다.
아이콘과 개수
표시자는 상자를 움직입니다
Base UI가 선택된 탭의 위치와 크기를 재서 --active-tab-left, --active-tab-width 같은 슬롯에 써 줍니다. 표시자는 그 값으로 left/top과 width/height를 애니메이션합니다.
이것은 빈 상자의 레이아웃 애니메이션이지 라벨의 transform이 아닙니다 — 글자가 든 것은 아무것도 움직이지 않고, 그것이 무-transform 규칙이 실제로 긋는 선입니다.
라이브러리에서 유일하게 논리 속성 대신 물리 속성(left)을 일부러 쓰는 곳이기도 합니다. --active-tab-left는 측정값입니다 — 리스트의 왼쪽 가장자리에서 선택된 탭까지의 픽셀 거리이고, RTL에서도 여전히 왼쪽으로부터의 거리입니다. 물리적 측정값을 논리 속성에 물리는 것이야말로 방향을 깨뜨리는 일이지 고치는 일이 아닙니다. 선이 놓이는 가장자리는 논리 속성입니다 — 그쪽은 실제로 뒤집히니까요.
activateOnFocus가 기본으로 꺼져 있는 이유
자동 활성화는 모든 패널이 이미 페이지에 있을 때만 친절합니다. 패널 하나가 데이터를 받아 오는 순간, 화살표로 탭 넷을 지나가는 것은 요청 네 번이 됩니다.
탭은 컨트롤 사다리를 씁니다
md 탭과 md Button은 같은 32px입니다. 그래야 탭 바를 툴바 안에 버튼 옆으로 놓아도 줄이 흐트러지지 않습니다.
접근성
Base UI가 탭 바를 버튼 한 줄이 아니라 탭 바로 만드는 것 전부를 소유합니다: 바 전체가 탭 스톱 하나가 되는 roving focus, 바가 흐르는 축의 화살표 키, Home과 End, tab / tabpanel 역할과 그 사이의 aria-controls 배선, 그리고 표시자를 선택된 탭 아래에 놓는 측정.
패널 안에 포커스 받을 것이 없으면 패널 자체가 포커스를 받습니다 — 그래야 키보드로 내용에 닿을 수 있고, 그때 브라우저 기본 테두리 대신 하우스 포커스 링이 그려집니다.