Tabs
Tabs
이 문서는 정리 중이에요. 문의 내용은 #_design_core 채널을 찾아주세요.
Content 1
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsPreview() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Installation
npx @seed-design/cli@latest add tabs
pnpm dlx @seed-design/cli@latest add tabs
yarn dlx @seed-design/cli@latest add tabs
bun x @seed-design/cli@latest add tabs
Props
TabsRoot
Prop | Type | Default |
---|---|---|
asChild? | boolean | false |
present? | boolean | false |
unmountOnExit? | boolean | false |
lazyMount? | boolean | false |
onValueChange? | ((value: string) => void) | - |
defaultValue? | string | - |
value? | string | - |
orientation? | "horizontal" | "vertical" | - |
stickyList? | boolean | false |
size? | "small" | "medium" | small |
contentLayout? | "fill" | "hug" | hug |
triggerLayout? | "fill" | "hug" | fill |
TabsList
Prop | Type | Default |
---|---|---|
asChild? | boolean | false |
TabsTrigger
Prop | Type | Default |
---|---|---|
disabled? | boolean | - |
value? | string | - |
notification? | boolean | - |
TabsCarousel
Prop | Type | Default |
---|---|---|
onSettle? | (() => void) | - |
dragThreshold? | number | - |
loop? | boolean | - |
autoHeight? | boolean | - |
swipeable? | boolean | - |
TabsContent
Prop | Type | Default |
---|---|---|
value? | string | - |
asChild? | boolean | false |
Examples
Layout Fill (Default)
Content 2
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsLayoutFill() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="2" triggerLayout="fill">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Layout Hug
Content 1
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsLayoutHug() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1" triggerLayout="hug">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Size Medium
Content 1
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsSizeMedium() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1" size="medium">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Size Small (Default)
Content 1
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsSizeSmall() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1" size="small">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Transition
TabsCarousel
컴포넌트로 TabsContent
컴포넌트들을 감싸면 탭 변경시 컨텐츠가 자연스럽게 전환됩니다.
Content 2
import { TabsRoot, TabsList, TabsTrigger, TabsCarousel, TabsContent } from "seed-design/ui/tabs";
export default function TabsTransition() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="2">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsCarousel>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsCarousel>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Swipeable
TabsCarousel
컴포넌트에 swipeable
속성을 추가하면 스와이프 제스처로 탭을 이동할 수 있습니다.
Content 2
import { TabsRoot, TabsList, TabsTrigger, TabsCarousel, TabsContent } from "seed-design/ui/tabs";
export default function TabsSwipeable() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="2">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsCarousel swipeable>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsCarousel>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Carousel Prevent Drag
Tabs.carouselPreventDrag
를 사용하면 특정 요소가 드래그 제스처에 반응하지 않도록 설정할 수 있습니다.
Scrollable area
import { Box, Tabs } from "@seed-design/react";
import { TabsCarousel, TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsCarouselPreventDrag() {
return (
<Box width="360px" height="480px">
<TabsRoot contentLayout="fill" defaultValue="1">
<TabsList>
<TabsTrigger value="1">Tab 1</TabsTrigger>
<TabsTrigger value="2">Tab 2</TabsTrigger>
</TabsList>
<TabsCarousel swipeable>
<TabsContent value="1">
<Box overflowX="scroll" {...Tabs.carouselPreventDrag}>
<Box width="1000px" height="100px" bg="bg.criticalWeak">
Scrollable area
</Box>
</Box>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Reiciendis ab ex accusantium
sit. Amet maxime eum molestiae nemo. Beatae sint omnis aut cumque doloremque fugit
perspiciatis rerum possimus, reiciendis eaque?
</TabsContent>
<TabsContent value="2">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
</TabsContent>
</TabsCarousel>
</TabsRoot>
</Box>
);
}
Disabled
Content 1
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsDisabled() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2" disabled>
라벨2
</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Notification
Content 1
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsNotification() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1">
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2" notification>
라벨2
</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content>Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content>Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content>Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Sticky List
탭이 전체화면을 차지하고, Tabs.List가 top에 고정되어 있는 경우 사용하는 예시입니다.
Content 1
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsStickyList() {
return (
// 600은 화면 높이라고 가정합니다.
<div style={{ width: "360px", height: "600px" }}>
<TabsRoot
defaultValue="1"
size="medium"
stickyList
style={{ height: "100%" }} // 탭 영역을 전체 화면으로 설정합니다.
>
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsContent value="1">
<Content height="1000px">Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content height="1000px">Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content height="1000px">Content 3</Content>
</TabsContent>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren<{ height: string }>) => {
const { height, children } = props;
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height,
background: "linear-gradient(to bottom, white, gray)",
}}
>
{children}
</div>
);
};
Standalone
TabContent를 사용하지 않고, 컨텐츠 영역을 온전히 소유하고 싶을 때 사용하는 예시입니다.
탭에서 제공하는 Swipe 기능을 사용할 수 없습니다.
Content 1
import { useState } from "react";
import { TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsStandalone() {
const [activeTab, setActiveTab] = useState("1");
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1" onValueChange={setActiveTab}>
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
{activeTab === "1" && (
<div>
<Content>Content 1</Content>
</div>
)}
{activeTab === "2" && (
<div>
<Content>Content 2</Content>
</div>
)}
{activeTab === "3" && (
<div>
<Content>Content 3</Content>
</div>
)}
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren) => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "300px",
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{props.children}
</div>
);
};
Dynamic Height
각 탭의 높이가 다를 때, 아래의 컨텐츠를 탭 아래에 바로 맞추기 위해서 사용하는 예시입니다.
탭이 자주 바뀌고, 탭에 네트워크 요청이 많은 경우 캐싱을 잘 고려해주세요.
Content 1
아래 컨텐츠
import { TabsCarousel, TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsDynamicHeight() {
return (
<div style={{ width: "360px" }}>
<TabsRoot defaultValue="1" lazyMount unmountOnExit>
<TabsList>
<TabsTrigger value="1">라벨1</TabsTrigger>
<TabsTrigger value="2">라벨2</TabsTrigger>
<TabsTrigger value="3">라벨3</TabsTrigger>
</TabsList>
<TabsCarousel autoHeight>
<TabsContent value="1">
<Content height="100px">Content 1</Content>
</TabsContent>
<TabsContent value="2">
<Content height="200px">Content 2</Content>
</TabsContent>
<TabsContent value="3">
<Content height="300px">Content 3</Content>
</TabsContent>
</TabsCarousel>
</TabsRoot>
<div style={{ height: "100px", backgroundColor: "gray" }}>아래 컨텐츠</div>
</div>
);
}
const Content = (props: React.PropsWithChildren<{ height: string }>) => {
const { height, children } = props;
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height,
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{children}
</div>
);
};
Scroll to Top
Content 1
import { RefObject, useRef, useState } from "react";
import { TabsCarousel, TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs";
export default function TabsScrollTop() {
const [currentTab, setCurrentTab] = useState("1");
const contentRefs: Record<string, RefObject<HTMLDivElement | null>> = {
"1": useRef(null),
"2": useRef(null),
};
const handleTriggerClick = (value: string) => {
if (value === currentTab) {
contentRefs[value].current?.scrollTo({ top: 0, behavior: "smooth" });
}
};
return (
<div style={{ width: "360px" }}>
<TabsRoot triggerLayout="fill" value={currentTab} onValueChange={setCurrentTab}>
<TabsList>
<TabsTrigger onClick={() => handleTriggerClick("1")} value="1">
라벨1
</TabsTrigger>
<TabsTrigger onClick={() => handleTriggerClick("2")} value="2">
라벨2
</TabsTrigger>
</TabsList>
<TabsCarousel swipeable>
<TabsContent ref={contentRefs["1"]} value="1" style={{ maxHeight: "200px" }}>
<Content height="1000px">Content 1</Content>
</TabsContent>
<TabsContent ref={contentRefs["2"]} value="2" style={{ maxHeight: "200px" }}>
<Content height="1000px">Content 2</Content>
</TabsContent>
</TabsCarousel>
</TabsRoot>
</div>
);
}
const Content = (props: React.PropsWithChildren<{ height: string }>) => {
const { height, children } = props;
return (
<div
style={{
display: "flex",
justifyContent: "center",
height,
backgroundColor: "var(--seed-color-bg-layer-default)",
}}
>
{children}
</div>
);
};
Last updated on