Tabs

Tabs는 관련된 콘텐츠를 탭 형태로 구성하여 사용자가 쉽게 전환할 수 있도록 하는 컴포넌트입니다. 키보드 내비게이션, 접근성, 다양한 스타일 변형을 지원합니다.
import { Tabs } from '@vapor-ui/core';
import { AiSmartieIcon, AssignmentIcon, ListIcon } from '@vapor-ui/icons';

export default function DefaultTabs() {
    return (
        <Tabs.Root defaultValue="overview" className="max-w-[200px] w-full mx-auto">
            <Tabs.List>
                <Tabs.Button value="overview">개요</Tabs.Button>
                <Tabs.Button value="features">기능</Tabs.Button>
                <Tabs.Button value="examples">예시</Tabs.Button>
            </Tabs.List>

            <Tabs.Panel value="overview" className="h-[100px] flex items-center justify-center">
                <AssignmentIcon size="32px" />
            </Tabs.Panel>

            <Tabs.Panel value="features" className="h-[100px] flex items-center justify-center">
                <AiSmartieIcon size="32px" />
            </Tabs.Panel>

            <Tabs.Panel value="examples" className="h-[100px] flex items-center justify-center">
                <ListIcon size="32px" />
            </Tabs.Panel>
        </Tabs.Root>
    );
}

Property


Size

Tabs의 크기를 지정합니다. sm, md, lg, xl 네 가지 크기를 제공합니다.

import { Tabs, VStack } from '@vapor-ui/core';

export default function TabsSize() {
    return (
        <VStack gap="$400">
            <Tabs.Root defaultValue="tab1" size="sm">
                <h4 className="text-sm font-medium mb-2">Small</h4>
                <Tabs.List>
                    <Tabs.Button value="tab1">Tab 1</Tabs.Button>
                    <Tabs.Button value="tab2">Tab 2</Tabs.Button>
                    <Tabs.Button value="tab3">Tab 3</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <Tabs.Root defaultValue="tab1" size="md">
                <h4 className="text-sm font-medium mb-2">Medium</h4>
                <Tabs.List>
                    <Tabs.Button value="tab1">Tab 1</Tabs.Button>
                    <Tabs.Button value="tab2">Tab 2</Tabs.Button>
                    <Tabs.Button value="tab3">Tab 3</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <Tabs.Root defaultValue="tab1" size="lg">
                <h4 className="text-sm font-medium mb-2">Large</h4>
                <Tabs.List>
                    <Tabs.Button value="tab1">Tab 1</Tabs.Button>
                    <Tabs.Button value="tab2">Tab 2</Tabs.Button>
                    <Tabs.Button value="tab3">Tab 3</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <Tabs.Root defaultValue="tab1" size="xl">
                <h4 className="text-sm font-medium mb-2">Extra Large</h4>
                <Tabs.List>
                    <Tabs.Button value="tab1">Tab 1</Tabs.Button>
                    <Tabs.Button value="tab2">Tab 2</Tabs.Button>
                    <Tabs.Button value="tab3">Tab 3</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>
        </VStack>
    );
}

Variant

Tabs의 스타일 변형을 설정합니다. linefill 두 가지 스타일을 제공합니다.

import { Tabs, VStack } from '@vapor-ui/core';

export default function TabsVariant() {
    return (
        <VStack gap="$400">
            <Tabs.Root defaultValue="home" variant="line">
                <h4 className="text-sm font-medium mb-4">Line 변형</h4>
                <Tabs.List className={'max-w-[400px] w-full mx-auto'}>
                    <Tabs.Button value="home"></Tabs.Button>
                    <Tabs.Button value="about">소개</Tabs.Button>
                    <Tabs.Button value="services">서비스</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <Tabs.Root defaultValue="home" variant="fill">
                <h4 className="text-sm font-medium mb-4">fill 변형</h4>
                <Tabs.List>
                    <Tabs.Button value="home"></Tabs.Button>
                    <Tabs.Button value="about">소개</Tabs.Button>
                    <Tabs.Button value="services">서비스</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>
        </VStack>
    );
}

Orientation

수평(horizontal)과 수직(vertical) 방향을 설정합니다.

import { Grid, Tabs } from '@vapor-ui/core';

export default function TabsOrientation() {
    return (
        <Grid.Root gap="$500" templateColumns="1fr 1fr">
            <Grid.Item>
                <h4 className="text-sm font-medium mb-4">수평 (Horizontal)</h4>
                <Tabs.Root defaultValue={1} orientation="horizontal">
                    <Tabs.List>
                        <Tabs.Button value={1}>Tab 1</Tabs.Button>
                        <Tabs.Button value={2}>Tab 2</Tabs.Button>
                        <Tabs.Button value={3}>Tab 3</Tabs.Button>
                    </Tabs.List>
                </Tabs.Root>
            </Grid.Item>

            <Grid.Item>
                <h4 className="text-sm font-medium mb-4 flex justify-center">수직 (Vertical)</h4>
                <Tabs.Root defaultValue={1} orientation="vertical" className="flex justify-center">
                    <Tabs.List>
                        <Tabs.Button value={1}>Tab 1</Tabs.Button>
                        <Tabs.Button value={2}>Tab 2</Tabs.Button>
                        <Tabs.Button value={3}>Tab 3</Tabs.Button>
                    </Tabs.List>
                </Tabs.Root>
            </Grid.Item>
        </Grid.Root>
    );
}

Controlled State

Tabs의 활성 상태를 외부에서 제어합니다.

'use client';

import { useState } from 'react';

import { Button, Tabs, VStack } from '@vapor-ui/core';

export default function TabsControlled() {
    const [activeTab, setActiveTab] = useState('profile');

    return (
        <VStack gap="$200">
            <Tabs.Root value={activeTab} onValueChange={setActiveTab}>
                <Tabs.List>
                    <Tabs.Button value="profile">프로필</Tabs.Button>
                    <Tabs.Button value="account">계정</Tabs.Button>
                    <Tabs.Button value="security">보안</Tabs.Button>
                    <Tabs.Button value="notifications">알림</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <div className="text-sm text-gray-600">
                현재 선택된 탭: <code className="bg-gray-100 px-1 rounded">{activeTab}</code>
            </div>

            <div className="flex gap-2">
                <Button onClick={() => setActiveTab('account')} className="">
                    계정 탭으로 이동
                </Button>
                <Button
                    colorPalette="success"
                    onClick={() => setActiveTab('security')}
                    className=""
                >
                    보안 탭으로 이동
                </Button>
            </div>
        </VStack>
    );
}

States

개별 탭 또는 전체 탭 그룹을 비활성화할 수 있습니다.

import { Tabs, VStack } from '@vapor-ui/core';

export default function TabsStates() {
    return (
        <VStack gap="$400">
            <Tabs.Root defaultValue="enabled">
                <h4 className="text-sm font-medium mb-4">개별 탭 비활성화</h4>
                <Tabs.List>
                    <Tabs.Button value="enabled">활성화 탭</Tabs.Button>
                    <Tabs.Button value="disabled" disabled>
                        비활성화 탭
                    </Tabs.Button>
                    <Tabs.Button value="normal">일반 탭</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <Tabs.Root defaultValue="enabled" disabled>
                <h4 className="text-sm font-medium mb-4">전체 탭 그룹 비활성화</h4>
                <Tabs.List>
                    <Tabs.Button value="enabled">활성화 탭</Tabs.Button>
                    <Tabs.Button value="disabled">비활성화 탭</Tabs.Button>
                    <Tabs.Button value="normal">일반 탭</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>
        </VStack>
    );
}

Examples


Keyboard Navigation

activateOnFocusloop props를 사용하여 키보드 내비게이션 동작을 세밀하게 제어할 수 있습니다.

import { Tabs, VStack } from '@vapor-ui/core';

export default function TabsKeyboard() {
    return (
        <VStack gap="$400">
            <Tabs.Root defaultValue="tab1" activateOnFocus={true}>
                <h4 className="text-sm font-medium mb-4">
                    포커스 시 활성화 <code>(activateOnFocus: true)</code>
                </h4>
                <Tabs.List>
                    <Tabs.Button value="tab1">탭 1</Tabs.Button>
                    <Tabs.Button value="tab2">탭 2</Tabs.Button>
                    <Tabs.Button value="tab3">탭 3</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <Tabs.Root defaultValue="tab1" activateOnFocus={false}>
                <h4 className="text-sm font-medium mb-4">
                    엔터/스페이스로 활성화 <code>(activateOnFocus: false)</code>
                </h4>
                <Tabs.List>
                    <Tabs.Button value="tab1">탭 1</Tabs.Button>
                    <Tabs.Button value="tab2">탭 2</Tabs.Button>
                    <Tabs.Button value="tab3">탭 3</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <Tabs.Root defaultValue="tab1" loop={true} activateOnFocus={false}>
                <h4 className="text-sm font-medium mb-4">
                    비순환 내비게이션 <code>(loop: false)</code>
                </h4>
                <Tabs.List loop={false}>
                    <Tabs.Button value="tab1">탭 1</Tabs.Button>
                    <Tabs.Button value="tab2">탭 2</Tabs.Button>
                    <Tabs.Button value="tab3">탭 3</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>
        </VStack>
    );
}

Without Panel

Tabs.Panel 없이 외부 상태로 콘텐츠를 관리할 수 있습니다.

'use client';

import { useState } from 'react';

import { Tabs, Text, VStack } from '@vapor-ui/core';

const CONTENT_MAP = {
    home: { title: '홈', description: '홈 페이지 콘텐츠입니다.' },
    about: { title: '소개', description: '회사 소개 콘텐츠입니다.' },
    services: { title: '서비스', description: '서비스 안내 콘텐츠입니다.' },
} as const;

export default function TabsWithoutPanel() {
    const [activeTab, setActiveTab] = useState<keyof typeof CONTENT_MAP>('home');

    return (
        <VStack gap="$300">
            <Tabs.Root
                value={activeTab}
                onValueChange={(value) => setActiveTab(value as keyof typeof CONTENT_MAP)}
            >
                <Tabs.List>
                    <Tabs.Button value="home"></Tabs.Button>
                    <Tabs.Button value="about">소개</Tabs.Button>
                    <Tabs.Button value="services">서비스</Tabs.Button>
                </Tabs.List>
            </Tabs.Root>

            <VStack padding="$400" border="1px solid" borderColor="$gray-200" borderRadius="$300">
                <Text typography="heading4">{CONTENT_MAP[activeTab].title}</Text>
                <Text typography="body2">{CONTENT_MAP[activeTab].description}</Text>
            </VStack>
        </VStack>
    );
}

Custom Indicator

Tabs.List는 기본적으로 Tabs.IndicatorPrimitive를 포함합니다. Indicator를 커스터마이징하려면 indicatorElement prop을 사용하세요.

import { Button, Tabs } from '@vapor-ui/core';

export default function TabsCustomIndicator() {
    return (
        <Tabs.Root defaultValue="home">
            <Tabs.List
                indicatorElement={
                    <Tabs.IndicatorPrimitive
                        className="bg-gradient-to-r from-red-600 to-orange-400"
                        style={{ height: '4px', borderRadius: '2px' }}
                    />
                }
            >
                <Button width="5rem">hi</Button>
                <Tabs.Button value="home" width="5rem">

                </Tabs.Button>
                <Tabs.Button value="about" width="5rem">
                    소개
                </Tabs.Button>
                <Tabs.Button value="services" width="5rem">
                    서비스
                </Tabs.Button>
            </Tabs.List>
        </Tabs.Root>
    );
}

Props Table


Tabs.Root

Loading component documentation...

Tabs.List

Loading component documentation...

Tabs.ListPrimitive

Loading component documentation...

Tabs.IndicatorPrimitive

Loading component documentation...

Tabs.Button

Loading component documentation...

Tabs.Panel

Loading component documentation...