
본 컴포넌트는 Next.js 환경에서 URL 쿼리 스트링을 상태로 활용하여, 새로고침이나 페이지 공유 시에도 유지되는 “서버 컴포넌트 친화적 탭”을 제공하도록 설계되었다.
| 파일명 | 유형 | 주요 역할 |
|---|---|---|
tabs.tsx |
client | Context API와 URL 상태를 결합하여 Tabs의 전체 로직을 관리하는 통합 파일 |
TabsRoot |
client | useSearchParams를 통해 현재 탭 상태를 구독하고 Context를 제공하는 최상위 컨테이너 |
TabsTrigger |
client | 클릭 시 URL을 업데이트하여 탭을 전환하는 버튼 요소 |
TabsContent |
client | 현재 URL의 파라미터와 일치할 때만 콘텐츠를 노출하는 래퍼 요소 |
모든 탭 구성 요소는 아래의 타입을 기반으로 한다.
defaultValue: string: 초기에 활성화될 기본 탭 값searchParamKey?: string: URL에 표시될 쿼리 키 (기본값: "tab")className?: string: 컨테이너 스타일 적용을 위한 클래스 주입value: string: 각 탭을 식별하기 위한 고유 값children: React.ReactNode: 내부 구성 요소⚠️ 주의: 한 페이지 내에서 여러 개의 탭을 사용할 경우, 서로 간섭하지 않도록 반드시 서로 다른 searchParamKey를 명시해야 합니다.
클릭 시 URL이 ?tab=account 등으로 변경되며 상태가 보존된다.
import { TabsRoot, TabsList, TabsTrigger, TabsContent } from "@/src/shared/ui/tabs";
export default function ProfilePage() {
return (
<TabsRoot defaultValue="account" className="w-full">
<TabsList className="bg-slate-100 p-1">
<TabsTrigger value="account">계정</TabsTrigger>
<TabsTrigger value="password">비밀번호</TabsTrigger>
</TabsList>
<div className="mt-4">
<TabsContent value="account">계정 설정 화면입니다.</TabsContent>
<TabsContent value="password">비밀번호 변경 화면입니다.</TabsContent>
</div>
</TabsRoot>
);
}
TabsContent 내부에 서버 컴포넌트를 배치하여 서버 데이터를 안전하게 불러올 수 있다.
// 이 예시는 서버 컴포넌트 내에서 데이터를 직접 다루는 구조입니다.
export default function Page() {
return (
<TabsRoot defaultValue="info">
<TabsList>
<TabsTrigger value="info">상세 정보</TabsTrigger>
</TabsList>
<TabsContent value="info">
{/* 서버 컴포넌트 호출 가능 */}
<ServerSideDetailComponent />
</TabsContent>
</TabsRoot>
);
}