TabPane#
박스형 탭 스트립과 각 탭이 소유한 콘텐츠 패널을 하나로 묶은 자체 완결형 탭 카드입니다. 탭 바만 제공하는 Tabs 와 달리,
CoreTabItem.content 슬롯의 위젯을 아래 패널에 함께 렌더합니다.
Live Preview#
class TabPaneExample extends StatefulComponent {
const TabPaneExample({super.key});
@override
State<TabPaneExample> createState() => _TabPaneExampleState();
}
class _TabPaneExampleState extends State<TabPaneExample> {
int _index = 0;
@override
Component build(BuildContext context) {
return TabPane(
tabs: [
CoreTabItem(
label: 'Account',
content: div(
[Text('Manage your account settings.').bodyMedium.onSurface],
classes: 'p-${CoreSpace.scale.space16}',
),
),
CoreTabItem(
label: 'Password',
content: div(
[Text('Change your password here.').bodyMedium.onSurface],
classes: 'p-${CoreSpace.scale.space16}',
),
),
],
selectedIndex: _index,
onChanged: (index) => setState(() => _index = index),
);
}
}
class TabPaneExample extends StatefulWidget {
const TabPaneExample({super.key});
@override
State<TabPaneExample> createState() => _TabPaneExampleState();
}
class _TabPaneExampleState extends State<TabPaneExample> {
int _index = 0;
@override
Widget build(BuildContext context) {
return TabPane(
tabs: [
CoreTabItem(
label: 'Account',
content: Padding(
padding: const EdgeInsets.all(CoreSpace.space16),
child: Text('Manage your account settings.').bodyMedium.onSurface,
),
),
CoreTabItem(
label: 'Password',
content: Padding(
padding: const EdgeInsets.all(CoreSpace.space16),
child: Text('Change your password here.').bodyMedium.onSurface,
),
),
],
selectedIndex: _index,
onChanged: (i) => setState(() => _index = i),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 탭과 그 콘텐츠 패널을 한 덩어리(카드)로 함께 보여줄 때
- 각 탭이 자체 콘텐츠를 소유하고 드래그로 순서를 바꿀 수 있어야 할 때
대신 다른 컴포넌트를 사용하세요:
Tabs: 탭 바만 필요하고 콘텐츠 영역을 직접 배치할 때 (pill / underline)Accordion: 모든 섹션을 한 페이지에서 펼치고 접을 때
기본 사용법 (Basic Usage)#
TabPane(
tabs: [
CoreTabItem(label: 'Account', content: accountPanel),
CoreTabItem(label: 'Password', content: passwordPanel),
],
selectedIndex: index,
onChanged: (i) => setState(() => index = i),
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
tabs |
List<CoreTabItem> |
필수 | 탭 목록 (content 슬롯이 콘텐츠 패널에 표시됨) |
selectedIndex | int | 필수 | 현재 포커스된 탭 인덱스 |
onChanged |
CoreValueChanged<int>? |
null |
탭 변경 콜백 |
reorderable |
bool |
false |
드래그로 탭 순서 변경 |
onReorder |
void Function(List<CoreTabItem>)? |
null |
탭 순서 변경 콜백 |
leading |
List<Widget> |
[] |
탭 바 앞쪽 위젯 |
trailing |
List<Widget> |
[] |
탭 바 뒤쪽 위젯 |
tabPaneStyle |
CoreTabPaneStyle? |
null |
인스턴스 스타일 |
스타일 시스템 (Style System)#
모든 chrome / dimensional 오버라이드는 CoreTabPaneStyle 단일 슬롯으로 흐릅니다. behaviour (tabs
/ selectedIndex / onChanged / reorderable) 는 위젯/컴포넌트 파라미터로 직접 전달합니다.
Resolve chain#
CoreTabPaneStyle.defaultX // 디자인 시스템 기본값
→ CoreTabPaneTheme.style // 프로젝트 공통
→ widget.tabPaneStyle // 인스턴스별
CoreTabPaneStyle 필드#
CoreTabPaneStyle 은 backgroundColor / borderColor / borderRadius
/ borderWidth / barHeight / tabPadding / tabSpacing
/ dragOpacity / contentTextStyle / clickableStyle(합성된 boxed-tab
Clickable 로 raw-forward) 를 가집니다.
동작 스펙 (Behavior)#
탭 전환#
- 탭 클릭 시 해당 콘텐츠 패널이 즉시 표시
onChanged콜백으로 탭 전환 이벤트 감지
드래그 정렬#
reorderable: true일 때 탭을 드래그하여 순서 변경onReorder콜백이 재정렬된CoreTabItem목록을 전달- 탭이 많아지면 탭 바가 가로 스크롤되며 가장자리에 페이드 효과 표시
접근성 (Accessibility)#
-
Web:
role="tab",role="tablist",role="tabpanel",aria-selected적용 - 선택된 탭은 박스형 chrome 으로 시각 구분되며 콘텐츠 패널과 연결됩니다
크로스 플랫폼 차이점 (Platform Differences)#
TabPane 은 Flutter / Web 에서 동일한 named properties API 를 사용합니다. 파라미터 이름·구조·동작이 양쪽 동일합니다.