V3 Improvements
V2(Sprout) 대비 V3에서 개선된 점을 소개합니다.
Concepts
Composition
V3에서는 컴포넌트를 조합하여 복잡한 UI를 구성하는 방법과 원칙을 제공합니다. as Prop, asChild Prop, 슬롯 등을 통해 컴포넌트를 조합할 수 있습니다.
Composition 페이지에서 자세히 설명합니다.
// Text 컴포넌트는 기본적으로 span 태그를 사용하지만, as Prop을 사용해 다른 태그로 변경할 수 있습니다.
<Text as="p">단락 텍스트</Text>
<Text as="span">인라인 텍스트</Text>
<Text as="h3">제목 텍스트</Text>
// ContextualFloatingButton은 기본적으로 button 태그를 사용하지만, asChild를 사용해 anchor로 변경할 수 있습니다.
<ContextualFloatingButton asChild>
<a href="/create" aria-label="Create">
<Icon svg={<IconPlusLine />} />
</a>
</ContextualFloatingButton>Snippet
V3에서는 자주 사용되는 UI 패턴을 스니펫으로 제공하여 개발 효율성을 높이는 방법을 제공합니다. Compound Components 패턴과 Snippet의 조합을 통해 복잡한 컴포넌트를 쉽게 구현할 수 있습니다.
Snippet 페이지에서 자세히 설명합니다.
<Checkbox.Root>
<Checkbox.Control>
<Checkbox.Indicator />
</Checkbox.Control>
<Checkbox.Label>Click me</Checkbox.Label>
<Checkbox.HiddenInput />
</Checkbox.Root>Icon Usage
컴포넌트 안에서 아이콘을 사용하는 방식이 달라졌습니다.
Icon Composition 페이지에서 자세히 설명합니다.
import { IconPlusFill } from "@karrotmarket/react-monochrome-icon";
import { PrefixIcon, SuffixIcon, Icon } from "@seed-design/react";
import { ActionButton } from "seed-design/ui/action-button";
export default function ActionButtonPrefixIcon() {
return (
<>
<BoxButton prefix={<IconPlusFill />} /> {/* Sprout */}
<BoxButton suffix={<IconPlusFill />} /> {/* Sprout */}
<ActionButton>
<PrefixIcon svg={<IconPlusFill />} />
Prefix Icon
</ActionButton>
<ActionButton>
<SuffixIcon svg={<IconPlusFill />} />
Suffix Icon
</ActionButton>
<ActionButton layout="iconOnly" aria-label="Add">
<Icon svg={<IconPlusFill />} />
</ActionButton>
</>
);
}Components
Avatar 업데이트
자세한 사용법은 Avatar 문서를 참고해주세요.
import { Avatar } from "@daangn/sprout-components-avatar";
import { Avatar } from "seed-design/ui/avatar"; // snippet 제공- size 옵션 재구성
- 이미지 로딩 실패 시 대체 콘텐츠를 위한
fallbackprop 제공
import { Flex } from "@seed-design/react";
import { Avatar, AvatarBadge } from "seed-design/ui/avatar";
import { IdentityPlaceholder } from "seed-design/ui/identity-placeholder";
export default function AvatarPreview() {
return (
<Flex gap="x4">
<Avatar
size="80"
src="https://avatars.githubusercontent.com/u/54893898?v=4"
fallback={<IdentityPlaceholder />}
>
<AvatarBadge>
<div style={{ background: "green", width: 20, height: 20, borderRadius: 9999 }} />
</AvatarBadge>
</Avatar>
<Avatar size="80" src={undefined} fallback={<IdentityPlaceholder />} />
</Flex>
);
}AlertDialog 업데이트
V2의 Dialog와 AlertDialog는 V3에서 AlertDialog로 제공돼요.
import { Dialog, DialogContainer, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@daangn/sprout-components-dialog";
import { AlertDialogAction, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogRoot, AlertDialogTitle, AlertDialogTrigger } from "seed-design/ui/alert-dialog"; // snippet 제공- 기존에
DialogHeader로만 구조화되어 있던 부분을 세분화 (AlertDialogContent,AlertDialogHeader,AlertDialogFooter) - 액션에 관한 슬롯 추가
AlertDialogAction AlertDialogTrigger로 명시적으로 trigger를 제공하거나 혹은openprop을 통해 외부에서 제어 가능
import { ResponsivePair } from "@seed-design/react";
import { ActionButton } from "seed-design/ui/action-button";
import {
AlertDialogAction,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogRoot,
AlertDialogTitle,
AlertDialogTrigger,
} from "seed-design/ui/alert-dialog";
const AlertDialogSingle = () => {
return (
// You can set z-index dialog with "--layer-index" custom property. useful for stackflow integration.
<AlertDialogRoot>
<AlertDialogTrigger asChild>
<ActionButton>열기</ActionButton>
</AlertDialogTrigger>
<AlertDialogContent layerIndex={50}>
<AlertDialogHeader>
<AlertDialogTitle>주의</AlertDialogTitle>
<AlertDialogDescription>이 작업은 되돌릴 수 없습니다.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<ResponsivePair gap="x2">
<AlertDialogAction variant="neutralWeak">취소</AlertDialogAction>
<AlertDialogAction variant="neutralSolid">확인</AlertDialogAction>
</ResponsivePair>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogRoot>
);
};
export default AlertDialogSingle;버튼 업데이트
BoxButton, TextButton
V2의 BoxButton과 TextButton은 V3에서 ActionButton으로 변경되었어요.
import { BoxButton, TextButton } from "@daangn/sprout-components-button";
import { ActionButton } from "seed-design/ui/action-button"; // snippet 제공- size 및 variant 옵션 재구성
xlargesize 제거Primary→Neutral SolidPrimary low→Neutral WeakSecondary→Neutral WeakDanger→Critical Solid- TextButton을 대체하는
ghostvariant 추가
layoutprop 추가 (withText,iconOnly)prefix,suffix: 아이콘 배치 방식이children으로 통합
import { ActionButton } from "seed-design/ui/action-button";
export default function ActionButtonPreview() {
return <ActionButton>라벨</ActionButton>;
}BoxToggleButton, CapsuleToggleButton
V2의 BoxToggleButton, CapsuleToggleButton은 V3에서 각각 ToggleButton, ReactionButton으로 변경되었어요.
import { BoxToggleButton, CapsuleToggleButton } from "@daangn/sprout-components-button";
import { ToggleButton } from "seed-design/ui/toggle-button"; // snippet 제공
import { ReactionButton } from "seed-design/ui/reaction-button"; // snippet 제공- size 옵션 재구성
import { useState } from "react";
import { ToggleButton } from "seed-design/ui/toggle-button";
export default function ToggleButtonPreview() {
const [pressed, setPressed] = useState(false);
return (
<ToggleButton pressed={pressed} onPressedChange={setPressed}>
{pressed ? "선택됨" : "미선택"}
</ToggleButton>
);
}import { IconFaceSmileCircleFill } from "@karrotmarket/react-monochrome-icon";
import { Count, PrefixIcon } from "@seed-design/react";
import { ReactionButton } from "seed-design/ui/reaction-button";
export default function ReactionButtonPreview() {
return (
<ReactionButton>
<PrefixIcon svg={<IconFaceSmileCircleFill />} />
도움돼요
<Count>1</Count>
</ReactionButton>
);
}Chip 업데이트
V2에서는 @daangn/sprout-components-chips 패키지에서 여러 칩 관련 컴포넌트들을 제공했어요. V3에서는 이러한 컴포넌트들이 목적에 따라 Chip으로 재구성되었어요.
layoutprop 추가 (withText,iconOnly)prefix,suffixprop 대신children으로 아이콘 전달countprop 제거
ChipButton
V2의 ChipButton은 V3에서 Chip.Button으로 변경되었어요.
import { ChipButton } from "@daangn/sprout-components-chips";
import { Chip } from "seed-design/ui/chip"; // snippet 제공import { HStack, VStack } from "@seed-design/react";
import { Chip } from "seed-design/ui/chip";
export default function ChipPreview() {
return (
<VStack gap="x3" align="center">
<HStack gap="x2">
<Chip.Button>
<Chip.Label>Button Chip</Chip.Label>
</Chip.Button>
<Chip.Toggle>
<Chip.Label>Toggle Chip</Chip.Label>
</Chip.Toggle>
</HStack>
<Chip.RadioRoot defaultValue="option1" aria-label="Options">
<HStack gap="x2">
<Chip.RadioItem value="option1">
<Chip.Label>Radio Chip 1</Chip.Label>
</Chip.RadioItem>
<Chip.RadioItem value="option2">
<Chip.Label>Radio Chip 2</Chip.Label>
</Chip.RadioItem>
</HStack>
</Chip.RadioRoot>
</VStack>
);
}ChipToggleButton
V2의 ChipToggleButton은 V3에서 Chip.Toggle으로 변경되었어요.
import { ChipToggleButton } from "@daangn/sprout-components-chips";
import { Chip } from "seed-design/ui/chip"; // snippet 제공ChipRadio, ChipRadioGroup
V2의 ChipRadio, ChipRadioGroup는 V3에서 Chip.RadioRoot과 Chip.RadioItem으로 변경되었어요.
import { ChipToggleButton, ChipRadio, ChipRadioGroup } from "@daangn/sprout-components-chips";
import { Chip } from "seed-design/ui/chip"; // snippet 제공ChipFilter
V2의 ChipFilter는 V3에서 제거되었어요. 필요한 경우 Chip.Button이나 Chip.Toggle로 대체할 수 있어요.
Checkbox 업데이트
자세한 사용법은 Checkbox 문서를 참고해주세요.
import { Checkbox } from "@daangn/sprout-components-checkbox";
import { Checkbox } from "seed-design/ui/checkbox"; // snippet 제공- size 및 variant 옵션 재구성
circlevariant 제거,square사용smallsize 제거
boldprop을weight으로 재구성
import { Checkbox } from "seed-design/ui/checkbox";
export default function CheckboxPreview() {
return <Checkbox label="Hello World" defaultChecked />;
}TextField 업데이트
V2에서는 TextField, MultilineTextField 컴포넌트를 따로 제공했지만, V3에서는 조합형 컴포넌트로 통합되었어요. 자세한 사용법은 TextField 및 MultilineTextField 문서를 참고해주세요.
import { TextField, MultilineTextField } from "@daangn/sprout-components-text-field";
import { TextField, TextFieldInput, TextFieldTextarea } from "seed-design/ui/text-field"; // snippet 제공- size 재구성
large→xlargemedium→largesmall→medium
TextFieldInput:<input>TextFieldTextarea:<textarea>maxGraphemeCountprop 추가 (기존maxLengthprop을 override하던 동작을 명시적으로 변경)
import { TextField, TextFieldInput } from "seed-design/ui/text-field";
export default function TextFieldPreview() {
return (
<TextField>
<TextFieldInput autoFocus />
</TextField>
);
}InlineAlert 업데이트
V2에서는 @daangn/sprout-components-inline-alert 패키지에서 여러 배너 관련 컴포넌트들을 제공했어요.
V3에서는 PageBanner 컴포넌트로 제공되고 있어요.
import { InlineBanner, ActionableInlineBanner, DismissibleInlineBanner } from "@daangn/sprout-components-banner";
import { PageBanner, ActionablePageBanner, DismissiblePageBanner } from "seed-design/ui/page-banner"; // snippet 제공- variant -> tone으로 변경 및 옵션 재구성
- variant 옵션 추가
import { VStack } from "@seed-design/react";
import {
ActionablePageBanner,
DismissiblePageBanner,
PageBanner,
} from "seed-design/ui/page-banner";
export default function PageBannerPreview() {
return (
<VStack gap="x4" width="full">
<PageBanner description="Ut veniam in ea ea anim laborum magna dolore ea laborum duis ut aute mollit amet." />
<ActionablePageBanner description="Ut veniam in ea ea anim laborum magna dolore ea laborum duis ut aute mollit amet." />
<DismissiblePageBanner description="Ut veniam in ea ea anim laborum magna dolore ea laborum duis ut aute mollit amet." />
</VStack>
);
}Callout 업데이트
자세한 사용법은 Callout 문서를 참고해주세요.
import { Callout, ActionableCallout, DismissibleCallout } from "@daangn/sprout-components-callout";
import { Callout, ActionableCallout, DismissibleCallout } from "seed-design/ui/callout"; // snippet 제공variant→tone으로 변경 및 옵션 재구성
import { VStack } from "@seed-design/react";
import { ActionableCallout, Callout, DismissibleCallout } from "seed-design/ui/callout";
export default function CalloutPreview() {
return (
<VStack gap="x4" width="full">
<Callout description="Aute nulla proident tempor minim eiusmod. In nostrud officia irure laborum." />
<ActionableCallout description="Aute nulla proident tempor minim eiusmod. In nostrud officia irure laborum." />
<DismissibleCallout description="Aute nulla proident tempor minim eiusmod. In nostrud officia irure laborum." />
</VStack>
);
}SelectBox 업데이트
V2에서는 @daangn/sprout-components-select-box 패키지에서 여러 SelectBox 관련 컴포넌트들을 제공했어요. V3에서는 이러한 컴포넌트들이 목적에 따라 재구성되었어요. 자세한 사용법은 CheckSelectBox 및 RadioSelectBox 문서를 참고해주세요.
SelectBoxCheck
import { SelectBoxCheck } from "@daangn/sprout-components-select-box";
import { CheckSelectBox, CheckSelectBoxGroup } from "seed-design/ui/select-box"; // snippet 제공SelectBoxCheck->CheckSelectBox
import { VStack } from "@seed-design/react";
import { CheckSelectBox, CheckSelectBoxGroup } from "seed-design/ui/select-box";
export default function CheckSelectBoxPreview() {
return (
<CheckSelectBoxGroup>
<VStack gap="spacingY.componentDefault">
<CheckSelectBox label="Apple" defaultChecked />
<CheckSelectBox
label="Melon"
description="Elit cupidatat dolore fugiat enim veniam culpa."
/>
<CheckSelectBox label="Mango" />
</VStack>
</CheckSelectBoxGroup>
);
}SelectBoxRadio, SelectBoxRadioGroup
import { SelectBoxRadio, SelectBoxRadioGroup } from "@daangn/sprout-components-select-box";
import { RadioSelectBoxItem, RadioSelectBoxRoot } from "seed-design/ui/select-box"; // snippet 제공SelectBoxRadio->RadioSelectBoxItemSelectBoxRadioGroup->RadioSelectBoxRoot
import { VStack } from "@seed-design/react";
import { RadioSelectBoxItem, RadioSelectBoxRoot } from "seed-design/ui/select-box";
export default function RadioSelectBoxPreview() {
return (
<RadioSelectBoxRoot defaultValue="apple" aria-label="Fruit">
<VStack gap="spacingY.componentDefault">
<RadioSelectBoxItem value="apple" label="Apple" />
<RadioSelectBoxItem
value="melon"
label="Melon"
description="Elit cupidatat dolore fugiat enim veniam culpa."
/>
<RadioSelectBoxItem value="mango" label="Mango" />
</VStack>
</RadioSelectBoxRoot>
);
}Tabs 업데이트
Tabs
자세한 사용법은 Tabs 문서를 참고해주세요.
import { Tabs, TabList, Tab, TabPanelGroup, TabPanel } from "@daangn/sprout-components-tabs";
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "seed-design/ui/tabs"; // snippet 제공- size 옵션 재구성
dot->notification으로 변경layout->triggerLayout으로 변경 (fill,hug)stickyListprop 추가: 스크롤 시 탭 목록 고정 가능- 컨텐츠의 layout도 조절 가능 (
contentLayout) - 렌더링 관련 prop 변경
isLazy->lazyMountlazyMode(unmount, keepMounted) ->unmountOnExit(boolean)
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>
);
};Switch 업데이트
자세한 사용법은 Switch 문서를 참고해주세요.
import { Switch } from "@daangn/sprout-components-switch";
import { Switch } from "seed-design/ui/switch"; // snippet 제공- size 옵션 재구성
- tone 옵션 추가
- children으로 제공되던 label 대신
labelprop 추가
import { Switch } from "seed-design/ui/switch";
export default function SwitchPreview() {
return <Switch defaultChecked />;
}Spinner 업데이트
Spinner는 V3에서 ProgressCircle로 변경되었어요.
import { Spinner } from "@daangn/sprout-components-spinner";
import { ProgressCircle } from "seed-design/ui/progress-circle"; // snippet 제공- size 및 tone 옵션 재구성
- 값이 결정된 상태(
valueprop 제공)와 미결정 상태(indeterminateprop) 지원
import { ProgressCircle } from "seed-design/ui/progress-circle";
export default function ProgressCirclePreview() {
return <ProgressCircle tone="neutral" size="40" />;
}Snackbar 업데이트
자세한 사용법은 Snackbar 문서를 참고해주세요.
import { SnackBar, useSnackbarAdapter } from "@daangn/sprout-components-snackbar";
import { Snackbar, SnackbarProvider, useSnackbar } from "seed-design/ui/snackbar"; // snippet 제공- variant 옵션 재구성
SnackbarProvider와useSnackbarhook을 통한 편리한 선언적 사용 방식 지원 (기존과 동일)
import { ActionButton } from "seed-design/ui/action-button";
import { Snackbar, SnackbarProvider, useSnackbarAdapter } from "seed-design/ui/snackbar";
function Component() {
const adapter = useSnackbarAdapter();
return (
<ActionButton
onClick={() =>
adapter.create({
timeout: 5000,
onClose: () => {},
render: () => <Snackbar message="알림 메세지" actionLabel="확인" onAction={() => {}} />,
})
}
>
실행
</ActionButton>
);
}
export default function SnackbarPreview() {
return (
<SnackbarProvider>
<Component />
</SnackbarProvider>
);
}HelpBubble 업데이트
자세한 사용법은 HelpBubble 문서를 참고해주세요.
import { HelpBubbleAnchor, HelpBubbleTrigger } from "@daangn/sprout-components-help-bubble";
import { HelpBubbleTrigger, HelpBubbleAnchor } from "seed-design/ui/help-bubble"; // snippet 제공import { IconILowercaseSerifCircleLine } from "@karrotmarket/react-monochrome-icon";
import { HelpBubbleTrigger } from "seed-design/ui/help-bubble";
import { ActionButton } from "seed-design/ui/action-button";
import { Icon } from "@seed-design/react";
export default function HelpBubblePreview() {
return (
<HelpBubbleTrigger defaultOpen title="아래 버튼이나 바깥 영역을 클릭해서 닫아보세요.">
<ActionButton variant="ghost" size="small" layout="iconOnly" aria-label="도움말">
<Icon svg={<IconILowercaseSerifCircleLine />} />
</ActionButton>
</HelpBubbleTrigger>
);
}FAB(Floating Action Button) 업데이트
V2의 FloatingActionButton과 ExtendedFAB는 용도에 따라 FloatingActionButton과 ContextualFloatingButton으로로 재구성되었어요.
import { FloatingActionButton } from "@daangn/sprout-components-floating-action-button";
import { ExtendedFab } from "@daangn/sprout-components-fab";
import { FloatingActionButton } from "seed-design/ui/floating-action-button"; // snippet 제공
import { ContextualFloatingButton } from "seed-design/ui/contextual-floating-button"; // snippet 제공import { FloatingActionButton } from "seed-design/ui/floating-action-button";
import IconPlusLine from "@karrotmarket/react-monochrome-icon/IconPlusLine";
export default function FloatingActionButtonPreview() {
return <FloatingActionButton icon={<IconPlusLine />} label="Example FAB" />;
}import { IconBellFill } from "@karrotmarket/react-monochrome-icon";
import { PrefixIcon } from "@seed-design/react";
import { ContextualFloatingButton } from "seed-design/ui/contextual-floating-button";
export default function ContextualFloatingButtonPreview() {
return (
<ContextualFloatingButton>
<PrefixIcon svg={<IconBellFill />} />
알림 설정
</ContextualFloatingButton>
);
}신규 컴포넌트
AppScreen: Stackflow AppScreen 컴포넌트BottomSheet및MenuSheetChipTabsErrorStateIdentityPlaceholderMannerTemp및MannerTempBadgePullToRefreshSegmentedControlSkeleton
컴포넌트는 꾸준히 추가되고 있습니다. 사이드바에서 최신 목록을 확인해보세요.
레이아웃 관련 컴포넌트
레이아웃 구성을 위한 다양한 컴포넌트가 제공됩니다.
import { Box, Flex, VStack, HStack } from "@seed-design/react";Last updated on