# Welcome, Vapor UI URL: /docs Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/index.mdx Vapor는 구름의 세 번째 디자인 시스템으로, 다양한 서브 패키지들로 구성되어 있습니다. 각 서브 패키지는 다음과 같은 역할을 수행합니다. # Icons URL: /docs/components/icons Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/icons.mdx Vapor UI 아이콘 라이브러리. 아이콘을 클릭하면 import 문이 복사됩니다. ## 설치 ```package-install @vapor-ui/icons ``` ## 사용법 ```tsx import { CheckCircleIcon, SearchOutlineIcon } from '@vapor-ui/icons'; function Example() { return ( <> ); } ``` ### Props | Prop | Type | Default | Description | | ------- | ----------------- | -------------- | ----------- | | `size` | `string` `number` | `24` | 아이콘 크기 (px) | | `color` | `string` | `currentColor` | 아이콘 색상 | ## 아이콘 스타일 아이콘을 클릭하면 import 문이 자동으로 복사됩니다. ## 아이콘 목록 ## Basic Icons | Icon Name | Import Statement | | --------------------------------------- | ------------------------------------------------------------------------- | | `AchievementIcon` | `import { AchievementIcon } from '@vapor-ui/icons'` | | `AddUserIcon` | `import { AddUserIcon } from '@vapor-ui/icons'` | | `AfghanistanColorIcon` | `import { AfghanistanColorIcon } from '@vapor-ui/icons'` | | `AiGoormeeIcon` | `import { AiGoormeeIcon } from '@vapor-ui/icons'` | | `AiSmartieIcon` | `import { AiSmartieIcon } from '@vapor-ui/icons'` | | `AirplayIcon` | `import { AirplayIcon } from '@vapor-ui/icons'` | | `AlbaniaColorIcon` | `import { AlbaniaColorIcon } from '@vapor-ui/icons'` | | `AlgeriaColorIcon` | `import { AlgeriaColorIcon } from '@vapor-ui/icons'` | | `AlgorithmIcon` | `import { AlgorithmIcon } from '@vapor-ui/icons'` | | `AndorraColorIcon` | `import { AndorraColorIcon } from '@vapor-ui/icons'` | | `AngolaColorIcon` | `import { AngolaColorIcon } from '@vapor-ui/icons'` | | `AntiguaAndBarbudaColorIcon` | `import { AntiguaAndBarbudaColorIcon } from '@vapor-ui/icons'` | | `AppleIcon` | `import { AppleIcon } from '@vapor-ui/icons'` | | `ArgentinaColorIcon` | `import { ArgentinaColorIcon } from '@vapor-ui/icons'` | | `ArmeniaColorIcon` | `import { ArmeniaColorIcon } from '@vapor-ui/icons'` | | `ArrowDownCircleIcon` | `import { ArrowDownCircleIcon } from '@vapor-ui/icons'` | | `AssignmentIcon` | `import { AssignmentIcon } from '@vapor-ui/icons'` | | `AustraliaColorIcon` | `import { AustraliaColorIcon } from '@vapor-ui/icons'` | | `AustriaColorIcon` | `import { AustriaColorIcon } from '@vapor-ui/icons'` | | `AwsIcon` | `import { AwsIcon } from '@vapor-ui/icons'` | | `AzerbaijanColorIcon` | `import { AzerbaijanColorIcon } from '@vapor-ui/icons'` | | `AzureIcon` | `import { AzureIcon } from '@vapor-ui/icons'` | | `BahamasColorIcon` | `import { BahamasColorIcon } from '@vapor-ui/icons'` | | `BahrainColorIcon` | `import { BahrainColorIcon } from '@vapor-ui/icons'` | | `BangladeshColorIcon` | `import { BangladeshColorIcon } from '@vapor-ui/icons'` | | `BarbadosColorIcon` | `import { BarbadosColorIcon } from '@vapor-ui/icons'` | | `BedIcon` | `import { BedIcon } from '@vapor-ui/icons'` | | `BelarusColorIcon` | `import { BelarusColorIcon } from '@vapor-ui/icons'` | | `BelgiumColorIcon` | `import { BelgiumColorIcon } from '@vapor-ui/icons'` | | `BelizeColorIcon` | `import { BelizeColorIcon } from '@vapor-ui/icons'` | | `BellOffIcon` | `import { BellOffIcon } from '@vapor-ui/icons'` | | `BellOnIcon` | `import { BellOnIcon } from '@vapor-ui/icons'` | | `BeninColorIcon` | `import { BeninColorIcon } from '@vapor-ui/icons'` | | `BhutanColorIcon` | `import { BhutanColorIcon } from '@vapor-ui/icons'` | | `BitbucketIcon` | `import { BitbucketIcon } from '@vapor-ui/icons'` | | `BlogColorIcon` | `import { BlogColorIcon } from '@vapor-ui/icons'` | | `BlogIcon` | `import { BlogIcon } from '@vapor-ui/icons'` | | `BoliviaColorIcon` | `import { BoliviaColorIcon } from '@vapor-ui/icons'` | | `BookIcon` | `import { BookIcon } from '@vapor-ui/icons'` | | `BookmarkIcon` | `import { BookmarkIcon } from '@vapor-ui/icons'` | | `BosniaAndHerzegovinaColorIcon` | `import { BosniaAndHerzegovinaColorIcon } from '@vapor-ui/icons'` | | `BotswanaColorIcon` | `import { BotswanaColorIcon } from '@vapor-ui/icons'` | | `BottomPlayerIcon` | `import { BottomPlayerIcon } from '@vapor-ui/icons'` | | `BranchIcon` | `import { BranchIcon } from '@vapor-ui/icons'` | | `BrazilColorIcon` | `import { BrazilColorIcon } from '@vapor-ui/icons'` | | `BreakpointIcon` | `import { BreakpointIcon } from '@vapor-ui/icons'` | | `BruneiColorIcon` | `import { BruneiColorIcon } from '@vapor-ui/icons'` | | `BuildIcon` | `import { BuildIcon } from '@vapor-ui/icons'` | | `BulgariaColorIcon` | `import { BulgariaColorIcon } from '@vapor-ui/icons'` | | `BurkinaFasoColorIcon` | `import { BurkinaFasoColorIcon } from '@vapor-ui/icons'` | | `BurundiColorIcon` | `import { BurundiColorIcon } from '@vapor-ui/icons'` | | `CafeIcon` | `import { CafeIcon } from '@vapor-ui/icons'` | | `CakeIcon` | `import { CakeIcon } from '@vapor-ui/icons'` | | `CalculatorIcon` | `import { CalculatorIcon } from '@vapor-ui/icons'` | | `CalendarIcon` | `import { CalendarIcon } from '@vapor-ui/icons'` | | `CallIcon` | `import { CallIcon } from '@vapor-ui/icons'` | | `CambodiaColorIcon` | `import { CambodiaColorIcon } from '@vapor-ui/icons'` | | `CameraIcon` | `import { CameraIcon } from '@vapor-ui/icons'` | | `CameroonColorIcon` | `import { CameroonColorIcon } from '@vapor-ui/icons'` | | `CampIcon` | `import { CampIcon } from '@vapor-ui/icons'` | | `CanadaColorIcon` | `import { CanadaColorIcon } from '@vapor-ui/icons'` | | `CapeVerdeColorIcon` | `import { CapeVerdeColorIcon } from '@vapor-ui/icons'` | | `CaptionIcon` | `import { CaptionIcon } from '@vapor-ui/icons'` | | `CarIcon` | `import { CarIcon } from '@vapor-ui/icons'` | | `CardsIcon` | `import { CardsIcon } from '@vapor-ui/icons'` | | `CaretDownIcon` | `import { CaretDownIcon } from '@vapor-ui/icons'` | | `CaretLeftIcon` | `import { CaretLeftIcon } from '@vapor-ui/icons'` | | `CaretRightIcon` | `import { CaretRightIcon } from '@vapor-ui/icons'` | | `CaretUpIcon` | `import { CaretUpIcon } from '@vapor-ui/icons'` | | `CentralAfricanRepublicColorIcon` | `import { CentralAfricanRepublicColorIcon } from '@vapor-ui/icons'` | | `CertificateIcon` | `import { CertificateIcon } from '@vapor-ui/icons'` | | `ChadColorIcon` | `import { ChadColorIcon } from '@vapor-ui/icons'` | | `ChapterIcon` | `import { ChapterIcon } from '@vapor-ui/icons'` | | `ChartPieIcon` | `import { ChartPieIcon } from '@vapor-ui/icons'` | | `ChatgptIcon` | `import { ChatgptIcon } from '@vapor-ui/icons'` | | `CheckCircleIcon` | `import { CheckCircleIcon } from '@vapor-ui/icons'` | | `CheckboxIcon` | `import { CheckboxIcon } from '@vapor-ui/icons'` | | `ChileColorIcon` | `import { ChileColorIcon } from '@vapor-ui/icons'` | | `ChinaColorIcon` | `import { ChinaColorIcon } from '@vapor-ui/icons'` | | `ChromeColorIcon` | `import { ChromeColorIcon } from '@vapor-ui/icons'` | | `ChromeIcon` | `import { ChromeIcon } from '@vapor-ui/icons'` | | `ClassIcon` | `import { ClassIcon } from '@vapor-ui/icons'` | | `CodeBlockIcon` | `import { CodeBlockIcon } from '@vapor-ui/icons'` | | `CodevisorIcon` | `import { CodevisorIcon } from '@vapor-ui/icons'` | | `CollaborationIcon` | `import { CollaborationIcon } from '@vapor-ui/icons'` | | `ColombiaColorIcon` | `import { ColombiaColorIcon } from '@vapor-ui/icons'` | | `ComorosColorIcon` | `import { ComorosColorIcon } from '@vapor-ui/icons'` | | `ComponentIcon` | `import { ComponentIcon } from '@vapor-ui/icons'` | | `ContainerIcon` | `import { ContainerIcon } from '@vapor-ui/icons'` | | `ContainerRunIcon` | `import { ContainerRunIcon } from '@vapor-ui/icons'` | | `ContainerShareIcon` | `import { ContainerShareIcon } from '@vapor-ui/icons'` | | `ContainerStopIcon` | `import { ContainerStopIcon } from '@vapor-ui/icons'` | | `ContainerToImageIcon` | `import { ContainerToImageIcon } from '@vapor-ui/icons'` | | `ControlCommonIcon` | `import { ControlCommonIcon } from '@vapor-ui/icons'` | | `CookIslandsColorIcon` | `import { CookIslandsColorIcon } from '@vapor-ui/icons'` | | `CopyIcon` | `import { CopyIcon } from '@vapor-ui/icons'` | | `CostaRicaColorIcon` | `import { CostaRicaColorIcon } from '@vapor-ui/icons'` | | `CouponIcon` | `import { CouponIcon } from '@vapor-ui/icons'` | | `CourseHistoryIcon` | `import { CourseHistoryIcon } from '@vapor-ui/icons'` | | `CourseIcon` | `import { CourseIcon } from '@vapor-ui/icons'` | | `CpuIcon` | `import { CpuIcon } from '@vapor-ui/icons'` | | `CreditCardIcon` | `import { CreditCardIcon } from '@vapor-ui/icons'` | | `CroatiaColorIcon` | `import { CroatiaColorIcon } from '@vapor-ui/icons'` | | `CubaColorIcon` | `import { CubaColorIcon } from '@vapor-ui/icons'` | | `CursorshareoffIcon` | `import { CursorshareoffIcon } from '@vapor-ui/icons'` | | `CursorshareonIcon` | `import { CursorshareonIcon } from '@vapor-ui/icons'` | | `CyprusColorIcon` | `import { CyprusColorIcon } from '@vapor-ui/icons'` | | `CzechRepublicColorIcon` | `import { CzechRepublicColorIcon } from '@vapor-ui/icons'` | | `DarkIcon` | `import { DarkIcon } from '@vapor-ui/icons'` | | `DashboardIcon` | `import { DashboardIcon } from '@vapor-ui/icons'` | | `DatabaseIcon` | `import { DatabaseIcon } from '@vapor-ui/icons'` | | `DebugContinueIcon` | `import { DebugContinueIcon } from '@vapor-ui/icons'` | | `DebugIcon` | `import { DebugIcon } from '@vapor-ui/icons'` | | `DemocraticRepublicOfTheCongoColorIcon` | `import { DemocraticRepublicOfTheCongoColorIcon } from '@vapor-ui/icons'` | | `DenmarkColorIcon` | `import { DenmarkColorIcon } from '@vapor-ui/icons'` | | `DeployPushIcon` | `import { DeployPushIcon } from '@vapor-ui/icons'` | | `DetailViewIcon` | `import { DetailViewIcon } from '@vapor-ui/icons'` | | `DevicesIcon` | `import { DevicesIcon } from '@vapor-ui/icons'` | | `DiscIcon` | `import { DiscIcon } from '@vapor-ui/icons'` | | `DiscordColorIcon` | `import { DiscordColorIcon } from '@vapor-ui/icons'` | | `DiscordIcon` | `import { DiscordIcon } from '@vapor-ui/icons'` | | `DiscussionIcon` | `import { DiscussionIcon } from '@vapor-ui/icons'` | | `DiskIcon` | `import { DiskIcon } from '@vapor-ui/icons'` | | `DislikeIcon` | `import { DislikeIcon } from '@vapor-ui/icons'` | | `DislikeThumbIcon` | `import { DislikeThumbIcon } from '@vapor-ui/icons'` | | `DividerIcon` | `import { DividerIcon } from '@vapor-ui/icons'` | | `DjiboutiColorIcon` | `import { DjiboutiColorIcon } from '@vapor-ui/icons'` | | `DockerIcon` | `import { DockerIcon } from '@vapor-ui/icons'` | | `DocktoBottomIcon` | `import { DocktoBottomIcon } from '@vapor-ui/icons'` | | `DocumentViewerIcon` | `import { DocumentViewerIcon } from '@vapor-ui/icons'` | | `DominicaColorIcon` | `import { DominicaColorIcon } from '@vapor-ui/icons'` | | `DominicanRepublicColorIcon` | `import { DominicanRepublicColorIcon } from '@vapor-ui/icons'` | | `DotIcon` | `import { DotIcon } from '@vapor-ui/icons'` | | `DownloadIcon` | `import { DownloadIcon } from '@vapor-ui/icons'` | | `DragIndicatorIcon` | `import { DragIndicatorIcon } from '@vapor-ui/icons'` | | `EastTimorColorIcon` | `import { EastTimorColorIcon } from '@vapor-ui/icons'` | | `EcuadorColorIcon` | `import { EcuadorColorIcon } from '@vapor-ui/icons'` | | `EditIcon` | `import { EditIcon } from '@vapor-ui/icons'` | | `EgyptColorIcon` | `import { EgyptColorIcon } from '@vapor-ui/icons'` | | `ElSalvadorColorIcon` | `import { ElSalvadorColorIcon } from '@vapor-ui/icons'` | | `EquatorialGuineaColorIcon` | `import { EquatorialGuineaColorIcon } from '@vapor-ui/icons'` | | `EraserIcon` | `import { EraserIcon } from '@vapor-ui/icons'` | | `EritreaColorIcon` | `import { EritreaColorIcon } from '@vapor-ui/icons'` | | `ErrorCircleIcon` | `import { ErrorCircleIcon } from '@vapor-ui/icons'` | | `EstoniaColorIcon` | `import { EstoniaColorIcon } from '@vapor-ui/icons'` | | `EswatiniColorIcon` | `import { EswatiniColorIcon } from '@vapor-ui/icons'` | | `EthiopiaColorIcon` | `import { EthiopiaColorIcon } from '@vapor-ui/icons'` | | `ExamIcon` | `import { ExamIcon } from '@vapor-ui/icons'` | | `ExamListIcon` | `import { ExamListIcon } from '@vapor-ui/icons'` | | `ExamReportIcon` | `import { ExamReportIcon } from '@vapor-ui/icons'` | | `ExploreIcon` | `import { ExploreIcon } from '@vapor-ui/icons'` | | `ExportIcon` | `import { ExportIcon } from '@vapor-ui/icons'` | | `ExportImageIcon` | `import { ExportImageIcon } from '@vapor-ui/icons'` | | `FacebookColorIcon` | `import { FacebookColorIcon } from '@vapor-ui/icons'` | | `FacebookIcon` | `import { FacebookIcon } from '@vapor-ui/icons'` | | `FigmaColorIcon` | `import { FigmaColorIcon } from '@vapor-ui/icons'` | | `FigmaIcon` | `import { FigmaIcon } from '@vapor-ui/icons'` | | `FijiColorIcon` | `import { FijiColorIcon } from '@vapor-ui/icons'` | | `FileAddIcon` | `import { FileAddIcon } from '@vapor-ui/icons'` | | `FileDeleteIcon` | `import { FileDeleteIcon } from '@vapor-ui/icons'` | | `FileIcon` | `import { FileIcon } from '@vapor-ui/icons'` | | `FilenewIcon` | `import { FilenewIcon } from '@vapor-ui/icons'` | | `FilterIcon` | `import { FilterIcon } from '@vapor-ui/icons'` | | `FinlandColorIcon` | `import { FinlandColorIcon } from '@vapor-ui/icons'` | | `FirefoxColorIcon` | `import { FirefoxColorIcon } from '@vapor-ui/icons'` | | `FlagIcon` | `import { FlagIcon } from '@vapor-ui/icons'` | | `FlaskIcon` | `import { FlaskIcon } from '@vapor-ui/icons'` | | `FlightIcon` | `import { FlightIcon } from '@vapor-ui/icons'` | | `FoldIcon` | `import { FoldIcon } from '@vapor-ui/icons'` | | `FolderIcon` | `import { FolderIcon } from '@vapor-ui/icons'` | | `FolderNewIcon` | `import { FolderNewIcon } from '@vapor-ui/icons'` | | `FolderSearchIcon` | `import { FolderSearchIcon } from '@vapor-ui/icons'` | | `ForkIcon` | `import { ForkIcon } from '@vapor-ui/icons'` | | `FranceColorIcon` | `import { FranceColorIcon } from '@vapor-ui/icons'` | | `FunctionIcon` | `import { FunctionIcon } from '@vapor-ui/icons'` | | `GabonColorIcon` | `import { GabonColorIcon } from '@vapor-ui/icons'` | | `GambiaColorIcon` | `import { GambiaColorIcon } from '@vapor-ui/icons'` | | `GameIcon` | `import { GameIcon } from '@vapor-ui/icons'` | | `GcpIcon` | `import { GcpIcon } from '@vapor-ui/icons'` | | `GeorgiaColorIcon` | `import { GeorgiaColorIcon } from '@vapor-ui/icons'` | | `GermanyColorIcon` | `import { GermanyColorIcon } from '@vapor-ui/icons'` | | `GhanaColorIcon` | `import { GhanaColorIcon } from '@vapor-ui/icons'` | | `GitIcon` | `import { GitIcon } from '@vapor-ui/icons'` | | `GithubColorIcon` | `import { GithubColorIcon } from '@vapor-ui/icons'` | | `GithubIcon` | `import { GithubIcon } from '@vapor-ui/icons'` | | `GitlabIcon` | `import { GitlabIcon } from '@vapor-ui/icons'` | | `GoogleCalendarIcon` | `import { GoogleCalendarIcon } from '@vapor-ui/icons'` | | `GoogleColorIcon` | `import { GoogleColorIcon } from '@vapor-ui/icons'` | | `GoogleDrawingIcon` | `import { GoogleDrawingIcon } from '@vapor-ui/icons'` | | `GoogleIcon` | `import { GoogleIcon } from '@vapor-ui/icons'` | | `GooglePresentationIcon` | `import { GooglePresentationIcon } from '@vapor-ui/icons'` | | `GoogleSpreadsheetIcon` | `import { GoogleSpreadsheetIcon } from '@vapor-ui/icons'` | | `GoormduinoIcon` | `import { GoormduinoIcon } from '@vapor-ui/icons'` | | `GpuIcon` | `import { GpuIcon } from '@vapor-ui/icons'` | | `GreeceColorIcon` | `import { GreeceColorIcon } from '@vapor-ui/icons'` | | `GrenadaColorIcon` | `import { GrenadaColorIcon } from '@vapor-ui/icons'` | | `GroupIcon` | `import { GroupIcon } from '@vapor-ui/icons'` | | `GuatemalaColorIcon` | `import { GuatemalaColorIcon } from '@vapor-ui/icons'` | | `GuestIcon` | `import { GuestIcon } from '@vapor-ui/icons'` | | `GuineaBissauColorIcon` | `import { GuineaBissauColorIcon } from '@vapor-ui/icons'` | | `GuineaColorIcon` | `import { GuineaColorIcon } from '@vapor-ui/icons'` | | `GuyanaColorIcon` | `import { GuyanaColorIcon } from '@vapor-ui/icons'` | | `HaitiColorIcon` | `import { HaitiColorIcon } from '@vapor-ui/icons'` | | `HeartIcon` | `import { HeartIcon } from '@vapor-ui/icons'` | | `HelpCircleIcon` | `import { HelpCircleIcon } from '@vapor-ui/icons'` | | `HelpIcon` | `import { HelpIcon } from '@vapor-ui/icons'` | | `HighlightViewIcon` | `import { HighlightViewIcon } from '@vapor-ui/icons'` | | `HomeIcon` | `import { HomeIcon } from '@vapor-ui/icons'` | | `HondurasColorIcon` | `import { HondurasColorIcon } from '@vapor-ui/icons'` | | `HourglassIcon` | `import { HourglassIcon } from '@vapor-ui/icons'` | | `HungaryColorIcon` | `import { HungaryColorIcon } from '@vapor-ui/icons'` | | `IcelandColorIcon` | `import { IcelandColorIcon } from '@vapor-ui/icons'` | | `IdCardIcon` | `import { IdCardIcon } from '@vapor-ui/icons'` | | `IdIcon` | `import { IdIcon } from '@vapor-ui/icons'` | | `IdeShareIcon` | `import { IdeShareIcon } from '@vapor-ui/icons'` | | `ImageIcon` | `import { ImageIcon } from '@vapor-ui/icons'` | | `ImagePackIcon` | `import { ImagePackIcon } from '@vapor-ui/icons'` | | `ImageToContainerIcon` | `import { ImageToContainerIcon } from '@vapor-ui/icons'` | | `ImportIcon` | `import { ImportIcon } from '@vapor-ui/icons'` | | `IndiaColorIcon` | `import { IndiaColorIcon } from '@vapor-ui/icons'` | | `IndonesiaColorIcon` | `import { IndonesiaColorIcon } from '@vapor-ui/icons'` | | `InfoCircleIcon` | `import { InfoCircleIcon } from '@vapor-ui/icons'` | | `InstagramColorIcon` | `import { InstagramColorIcon } from '@vapor-ui/icons'` | | `InstagramIcon` | `import { InstagramIcon } from '@vapor-ui/icons'` | | `IntelliSenseClassIcon` | `import { IntelliSenseClassIcon } from '@vapor-ui/icons'` | | `IntelliSenseColorIcon` | `import { IntelliSenseColorIcon } from '@vapor-ui/icons'` | | `IntelliSenseConstantIcon` | `import { IntelliSenseConstantIcon } from '@vapor-ui/icons'` | | `IntelliSenseEnumIcon` | `import { IntelliSenseEnumIcon } from '@vapor-ui/icons'` | | `IntelliSenseEventIcon` | `import { IntelliSenseEventIcon } from '@vapor-ui/icons'` | | `IntelliSenseFunctionIcon` | `import { IntelliSenseFunctionIcon } from '@vapor-ui/icons'` | | `IntelliSenseInterfaceIcon` | `import { IntelliSenseInterfaceIcon } from '@vapor-ui/icons'` | | `IntelliSenseModuleIcon` | `import { IntelliSenseModuleIcon } from '@vapor-ui/icons'` | | `IntelliSenseNullIcon` | `import { IntelliSenseNullIcon } from '@vapor-ui/icons'` | | `IntelliSenseOperatorIcon` | `import { IntelliSenseOperatorIcon } from '@vapor-ui/icons'` | | `IntelliSensePropertyIcon` | `import { IntelliSensePropertyIcon } from '@vapor-ui/icons'` | | `IntelliSenseSnippetIcon` | `import { IntelliSenseSnippetIcon } from '@vapor-ui/icons'` | | `IntelliSenseStructureIcon` | `import { IntelliSenseStructureIcon } from '@vapor-ui/icons'` | | `IntelliSenseTextIcon` | `import { IntelliSenseTextIcon } from '@vapor-ui/icons'` | | `IntelliSenseUnitIcon` | `import { IntelliSenseUnitIcon } from '@vapor-ui/icons'` | | `IntelliSenseValueIcon` | `import { IntelliSenseValueIcon } from '@vapor-ui/icons'` | | `IntellijColorIcon` | `import { IntellijColorIcon } from '@vapor-ui/icons'` | | `IranColorIcon` | `import { IranColorIcon } from '@vapor-ui/icons'` | | `IraqColorIcon` | `import { IraqColorIcon } from '@vapor-ui/icons'` | | `IrelandColorIcon` | `import { IrelandColorIcon } from '@vapor-ui/icons'` | | `IsraelColorIcon` | `import { IsraelColorIcon } from '@vapor-ui/icons'` | | `ItalicIcon` | `import { ItalicIcon } from '@vapor-ui/icons'` | | `ItalyColorIcon` | `import { ItalyColorIcon } from '@vapor-ui/icons'` | | `IvoryCoastColorIcon` | `import { IvoryCoastColorIcon } from '@vapor-ui/icons'` | | `JamaicaColorIcon` | `import { JamaicaColorIcon } from '@vapor-ui/icons'` | | `JapanColorIcon` | `import { JapanColorIcon } from '@vapor-ui/icons'` | | `JiraIcon` | `import { JiraIcon } from '@vapor-ui/icons'` | | `JordanColorIcon` | `import { JordanColorIcon } from '@vapor-ui/icons'` | | `JupyterColorIcon` | `import { JupyterColorIcon } from '@vapor-ui/icons'` | | `JupyterlabColorIcon` | `import { JupyterlabColorIcon } from '@vapor-ui/icons'` | | `JupyterlabIcon` | `import { JupyterlabIcon } from '@vapor-ui/icons'` | | `KakaoIcon` | `import { KakaoIcon } from '@vapor-ui/icons'` | | `KazakhstanColorIcon` | `import { KazakhstanColorIcon } from '@vapor-ui/icons'` | | `KenyaColorIcon` | `import { KenyaColorIcon } from '@vapor-ui/icons'` | | `KeyboardIcon` | `import { KeyboardIcon } from '@vapor-ui/icons'` | | `KeyboardTabIcon` | `import { KeyboardTabIcon } from '@vapor-ui/icons'` | | `KidIcon` | `import { KidIcon } from '@vapor-ui/icons'` | | `KiribatiColorIcon` | `import { KiribatiColorIcon } from '@vapor-ui/icons'` | | `KosovoColorIcon` | `import { KosovoColorIcon } from '@vapor-ui/icons'` | | `KrampolineIcon` | `import { KrampolineIcon } from '@vapor-ui/icons'` | | `KubernatesIcon` | `import { KubernatesIcon } from '@vapor-ui/icons'` | | `KuwaitColorIcon` | `import { KuwaitColorIcon } from '@vapor-ui/icons'` | | `KyrgyzstanColorIcon` | `import { KyrgyzstanColorIcon } from '@vapor-ui/icons'` | | `LaosColorIcon` | `import { LaosColorIcon } from '@vapor-ui/icons'` | | `LatviaColorIcon` | `import { LatviaColorIcon } from '@vapor-ui/icons'` | | `LebanonColorIcon` | `import { LebanonColorIcon } from '@vapor-ui/icons'` | | `LesothoColorIcon` | `import { LesothoColorIcon } from '@vapor-ui/icons'` | | `LiberiaColorIcon` | `import { LiberiaColorIcon } from '@vapor-ui/icons'` | | `LibyaColorIcon` | `import { LibyaColorIcon } from '@vapor-ui/icons'` | | `LicenseIcon` | `import { LicenseIcon } from '@vapor-ui/icons'` | | `LiechtensteinColorIcon` | `import { LiechtensteinColorIcon } from '@vapor-ui/icons'` | | `LightIcon` | `import { LightIcon } from '@vapor-ui/icons'` | | `LightbulbIcon` | `import { LightbulbIcon } from '@vapor-ui/icons'` | | `LightningIcon` | `import { LightningIcon } from '@vapor-ui/icons'` | | `LikeIcon` | `import { LikeIcon } from '@vapor-ui/icons'` | | `LikeThumbIcon` | `import { LikeThumbIcon } from '@vapor-ui/icons'` | | `LinkedinIcon` | `import { LinkedinIcon } from '@vapor-ui/icons'` | | `ListIcon` | `import { ListIcon } from '@vapor-ui/icons'` | | `ListNumberedIcon` | `import { ListNumberedIcon } from '@vapor-ui/icons'` | | `LithuaniaColorIcon` | `import { LithuaniaColorIcon } from '@vapor-ui/icons'` | | `LiveLessonIcon` | `import { LiveLessonIcon } from '@vapor-ui/icons'` | | `LocationIcon` | `import { LocationIcon } from '@vapor-ui/icons'` | | `LockIcon` | `import { LockIcon } from '@vapor-ui/icons'` | | `LuxembourgColorIcon` | `import { LuxembourgColorIcon } from '@vapor-ui/icons'` | | `MadagascarColorIcon` | `import { MadagascarColorIcon } from '@vapor-ui/icons'` | | `MagicWandIcon` | `import { MagicWandIcon } from '@vapor-ui/icons'` | | `MailIcon` | `import { MailIcon } from '@vapor-ui/icons'` | | `MalawiColorIcon` | `import { MalawiColorIcon } from '@vapor-ui/icons'` | | `MalaysiaColorIcon` | `import { MalaysiaColorIcon } from '@vapor-ui/icons'` | | `MaldivesColorIcon` | `import { MaldivesColorIcon } from '@vapor-ui/icons'` | | `MaliColorIcon` | `import { MaliColorIcon } from '@vapor-ui/icons'` | | `MaltaColorIcon` | `import { MaltaColorIcon } from '@vapor-ui/icons'` | | `MarkModeIcon` | `import { MarkModeIcon } from '@vapor-ui/icons'` | | `MarkdownIcon` | `import { MarkdownIcon } from '@vapor-ui/icons'` | | `MarshallIslandsColorIcon` | `import { MarshallIslandsColorIcon } from '@vapor-ui/icons'` | | `MauritaniaColorIcon` | `import { MauritaniaColorIcon } from '@vapor-ui/icons'` | | `MauritiusColorIcon` | `import { MauritiusColorIcon } from '@vapor-ui/icons'` | | `MediumIcon` | `import { MediumIcon } from '@vapor-ui/icons'` | | `MemoIcon` | `import { MemoIcon } from '@vapor-ui/icons'` | | `MemoryIcon` | `import { MemoryIcon } from '@vapor-ui/icons'` | | `MessageIcon` | `import { MessageIcon } from '@vapor-ui/icons'` | | `MethodIcon` | `import { MethodIcon } from '@vapor-ui/icons'` | | `MexicoColorIcon` | `import { MexicoColorIcon } from '@vapor-ui/icons'` | | `MicOffIcon` | `import { MicOffIcon } from '@vapor-ui/icons'` | | `MicOnIcon` | `import { MicOnIcon } from '@vapor-ui/icons'` | | `MicronesiaColorIcon` | `import { MicronesiaColorIcon } from '@vapor-ui/icons'` | | `MinusBoxIcon` | `import { MinusBoxIcon } from '@vapor-ui/icons'` | | `MoldovaColorIcon` | `import { MoldovaColorIcon } from '@vapor-ui/icons'` | | `MonacoColorIcon` | `import { MonacoColorIcon } from '@vapor-ui/icons'` | | `MongoliaColorIcon` | `import { MongoliaColorIcon } from '@vapor-ui/icons'` | | `MontenegroColorIcon` | `import { MontenegroColorIcon } from '@vapor-ui/icons'` | | `MoroccoColorIcon` | `import { MoroccoColorIcon } from '@vapor-ui/icons'` | | `MovieIcon` | `import { MovieIcon } from '@vapor-ui/icons'` | | `MozambiqueColorIcon` | `import { MozambiqueColorIcon } from '@vapor-ui/icons'` | | `MyanmarColorIcon` | `import { MyanmarColorIcon } from '@vapor-ui/icons'` | | `MysqlColorIcon` | `import { MysqlColorIcon } from '@vapor-ui/icons'` | | `MysqlIcon` | `import { MysqlIcon } from '@vapor-ui/icons'` | | `NamibiaColorIcon` | `import { NamibiaColorIcon } from '@vapor-ui/icons'` | | `NauruColorIcon` | `import { NauruColorIcon } from '@vapor-ui/icons'` | | `NaverIcon` | `import { NaverIcon } from '@vapor-ui/icons'` | | `NaverblogColorIcon` | `import { NaverblogColorIcon } from '@vapor-ui/icons'` | | `NaverblogIcon` | `import { NaverblogIcon } from '@vapor-ui/icons'` | | `NepalColorIcon` | `import { NepalColorIcon } from '@vapor-ui/icons'` | | `NetherlandsColorIcon` | `import { NetherlandsColorIcon } from '@vapor-ui/icons'` | | `NetworkIcon` | `import { NetworkIcon } from '@vapor-ui/icons'` | | `NewZealandColorIcon` | `import { NewZealandColorIcon } from '@vapor-ui/icons'` | | `NextIcon` | `import { NextIcon } from '@vapor-ui/icons'` | | `NicaraguaColorIcon` | `import { NicaraguaColorIcon } from '@vapor-ui/icons'` | | `NigerColorIcon` | `import { NigerColorIcon } from '@vapor-ui/icons'` | | `NigeriaColorIcon` | `import { NigeriaColorIcon } from '@vapor-ui/icons'` | | `NiueColorIcon` | `import { NiueColorIcon } from '@vapor-ui/icons'` | | `NoImageIcon` | `import { NoImageIcon } from '@vapor-ui/icons'` | | `NoUserIcon` | `import { NoUserIcon } from '@vapor-ui/icons'` | | `NorthMacedoniaColorIcon` | `import { NorthMacedoniaColorIcon } from '@vapor-ui/icons'` | | `NorwayColorIcon` | `import { NorwayColorIcon } from '@vapor-ui/icons'` | | `NoticeBoardIcon` | `import { NoticeBoardIcon } from '@vapor-ui/icons'` | | `NoticeCircleIcon` | `import { NoticeCircleIcon } from '@vapor-ui/icons'` | | `NotionIcon` | `import { NotionIcon } from '@vapor-ui/icons'` | | `ObjectIcon` | `import { ObjectIcon } from '@vapor-ui/icons'` | | `OmanColorIcon` | `import { OmanColorIcon } from '@vapor-ui/icons'` | | `OpenFileIcon` | `import { OpenFileIcon } from '@vapor-ui/icons'` | | `OpenFolderIcon` | `import { OpenFolderIcon } from '@vapor-ui/icons'` | | `OperaColorIcon` | `import { OperaColorIcon } from '@vapor-ui/icons'` | | `OrganizationIcon` | `import { OrganizationIcon } from '@vapor-ui/icons'` | | `PakistanColorIcon` | `import { PakistanColorIcon } from '@vapor-ui/icons'` | | `PalauColorIcon` | `import { PalauColorIcon } from '@vapor-ui/icons'` | | `PanamaColorIcon` | `import { PanamaColorIcon } from '@vapor-ui/icons'` | | `PanelOpenIcon` | `import { PanelOpenIcon } from '@vapor-ui/icons'` | | `PapuaNewGuineaColorIcon` | `import { PapuaNewGuineaColorIcon } from '@vapor-ui/icons'` | | `ParaguayColorIcon` | `import { ParaguayColorIcon } from '@vapor-ui/icons'` | | `ParentsIcon` | `import { ParentsIcon } from '@vapor-ui/icons'` | | `PauseIcon` | `import { PauseIcon } from '@vapor-ui/icons'` | | `PaycoIcon` | `import { PaycoIcon } from '@vapor-ui/icons'` | | `PaypalColorIcon` | `import { PaypalColorIcon } from '@vapor-ui/icons'` | | `PcIcon` | `import { PcIcon } from '@vapor-ui/icons'` | | `PdfIcon` | `import { PdfIcon } from '@vapor-ui/icons'` | | `PeruColorIcon` | `import { PeruColorIcon } from '@vapor-ui/icons'` | | `PhilippinesColorIcon` | `import { PhilippinesColorIcon } from '@vapor-ui/icons'` | | `PhoneIcon` | `import { PhoneIcon } from '@vapor-ui/icons'` | | `PinSetIcon` | `import { PinSetIcon } from '@vapor-ui/icons'` | | `PipetteIcon` | `import { PipetteIcon } from '@vapor-ui/icons'` | | `PlansIcon` | `import { PlansIcon } from '@vapor-ui/icons'` | | `PlayIcon` | `import { PlayIcon } from '@vapor-ui/icons'` | | `PlugInIcon` | `import { PlugInIcon } from '@vapor-ui/icons'` | | `PlugOutIcon` | `import { PlugOutIcon } from '@vapor-ui/icons'` | | `PlusBoxIcon` | `import { PlusBoxIcon } from '@vapor-ui/icons'` | | `PolandColorIcon` | `import { PolandColorIcon } from '@vapor-ui/icons'` | | `PortforwardingIcon` | `import { PortforwardingIcon } from '@vapor-ui/icons'` | | `PortugalColorIcon` | `import { PortugalColorIcon } from '@vapor-ui/icons'` | | `PowerIcon` | `import { PowerIcon } from '@vapor-ui/icons'` | | `PreIcon` | `import { PreIcon } from '@vapor-ui/icons'` | | `PresentScreenIcon` | `import { PresentScreenIcon } from '@vapor-ui/icons'` | | `PreviewIcon` | `import { PreviewIcon } from '@vapor-ui/icons'` | | `PrintIcon` | `import { PrintIcon } from '@vapor-ui/icons'` | | `ProductHuntColorIcon` | `import { ProductHuntColorIcon } from '@vapor-ui/icons'` | | `ProjectIcon` | `import { ProjectIcon } from '@vapor-ui/icons'` | | `ProjectOpenIcon` | `import { ProjectOpenIcon } from '@vapor-ui/icons'` | | `ProjectSettingIcon` | `import { ProjectSettingIcon } from '@vapor-ui/icons'` | | `PropertyIcon` | `import { PropertyIcon } from '@vapor-ui/icons'` | | `PsychologyIcon` | `import { PsychologyIcon } from '@vapor-ui/icons'` | | `PublishIcon` | `import { PublishIcon } from '@vapor-ui/icons'` | | `QatarColorIcon` | `import { QatarColorIcon } from '@vapor-ui/icons'` | | `QnAIcon` | `import { QnAIcon } from '@vapor-ui/icons'` | | `QuoteIcon` | `import { QuoteIcon } from '@vapor-ui/icons'` | | `ReferenceIcon` | `import { ReferenceIcon } from '@vapor-ui/icons'` | | `RemoteIcon` | `import { RemoteIcon } from '@vapor-ui/icons'` | | `RemoteOffIcon` | `import { RemoteOffIcon } from '@vapor-ui/icons'` | | `ReplaceIcon` | `import { ReplaceIcon } from '@vapor-ui/icons'` | | `RepublicOfTheCongoColorIcon` | `import { RepublicOfTheCongoColorIcon } from '@vapor-ui/icons'` | | `ResultManagementIcon` | `import { ResultManagementIcon } from '@vapor-ui/icons'` | | `RewardedAdsIcon` | `import { RewardedAdsIcon } from '@vapor-ui/icons'` | | `RomaniaColorIcon` | `import { RomaniaColorIcon } from '@vapor-ui/icons'` | | `RouteIcon` | `import { RouteIcon } from '@vapor-ui/icons'` | | `RstudioColorIcon` | `import { RstudioColorIcon } from '@vapor-ui/icons'` | | `RunIcon` | `import { RunIcon } from '@vapor-ui/icons'` | | `RussiaColorIcon` | `import { RussiaColorIcon } from '@vapor-ui/icons'` | | `RwandaColorIcon` | `import { RwandaColorIcon } from '@vapor-ui/icons'` | | `SaintKittsAndNevisColorIcon` | `import { SaintKittsAndNevisColorIcon } from '@vapor-ui/icons'` | | `SaintLuciaColorIcon` | `import { SaintLuciaColorIcon } from '@vapor-ui/icons'` | | `SaintVincentAndTheGrenadinesColorIcon` | `import { SaintVincentAndTheGrenadinesColorIcon } from '@vapor-ui/icons'` | | `SamoaColorIcon` | `import { SamoaColorIcon } from '@vapor-ui/icons'` | | `SanMarinoColorIcon` | `import { SanMarinoColorIcon } from '@vapor-ui/icons'` | | `SaoTomeAndPrincipeColorIcon` | `import { SaoTomeAndPrincipeColorIcon } from '@vapor-ui/icons'` | | `SaudiArabiaColorIcon` | `import { SaudiArabiaColorIcon } from '@vapor-ui/icons'` | | `SaveAsIcon` | `import { SaveAsIcon } from '@vapor-ui/icons'` | | `SaveIcon` | `import { SaveIcon } from '@vapor-ui/icons'` | | `SavingIcon` | `import { SavingIcon } from '@vapor-ui/icons'` | | `SbomIcon` | `import { SbomIcon } from '@vapor-ui/icons'` | | `SchoolIcon` | `import { SchoolIcon } from '@vapor-ui/icons'` | | `SendIcon` | `import { SendIcon } from '@vapor-ui/icons'` | | `SenegalColorIcon` | `import { SenegalColorIcon } from '@vapor-ui/icons'` | | `SentryIcon` | `import { SentryIcon } from '@vapor-ui/icons'` | | `SerbiaColorIcon` | `import { SerbiaColorIcon } from '@vapor-ui/icons'` | | `SettingIcon` | `import { SettingIcon } from '@vapor-ui/icons'` | | `SeychellesColorIcon` | `import { SeychellesColorIcon } from '@vapor-ui/icons'` | | `ShareIcon` | `import { ShareIcon } from '@vapor-ui/icons'` | | `ShoppingCartIcon` | `import { ShoppingCartIcon } from '@vapor-ui/icons'` | | `SideNavIcon` | `import { SideNavIcon } from '@vapor-ui/icons'` | | `SierraLeoneColorIcon` | `import { SierraLeoneColorIcon } from '@vapor-ui/icons'` | | `SingaporeColorIcon` | `import { SingaporeColorIcon } from '@vapor-ui/icons'` | | `SlackColorIcon` | `import { SlackColorIcon } from '@vapor-ui/icons'` | | `SlackIcon` | `import { SlackIcon } from '@vapor-ui/icons'` | | `SlotIcon` | `import { SlotIcon } from '@vapor-ui/icons'` | | `SlovakiaColorIcon` | `import { SlovakiaColorIcon } from '@vapor-ui/icons'` | | `SloveniaColorIcon` | `import { SloveniaColorIcon } from '@vapor-ui/icons'` | | `SolomonIslandsColorIcon` | `import { SolomonIslandsColorIcon } from '@vapor-ui/icons'` | | `SomaliaColorIcon` | `import { SomaliaColorIcon } from '@vapor-ui/icons'` | | `SoundOffIcon` | `import { SoundOffIcon } from '@vapor-ui/icons'` | | `SoundOnIcon` | `import { SoundOnIcon } from '@vapor-ui/icons'` | | `SourcecodeIcon` | `import { SourcecodeIcon } from '@vapor-ui/icons'` | | `SouthAfricaColorIcon` | `import { SouthAfricaColorIcon } from '@vapor-ui/icons'` | | `SouthKoreaColorIcon` | `import { SouthKoreaColorIcon } from '@vapor-ui/icons'` | | `SouthSudanColorIcon` | `import { SouthSudanColorIcon } from '@vapor-ui/icons'` | | `SpainColorIcon` | `import { SpainColorIcon } from '@vapor-ui/icons'` | | `SplitIcon` | `import { SplitIcon } from '@vapor-ui/icons'` | | `SriLankaColorIcon` | `import { SriLankaColorIcon } from '@vapor-ui/icons'` | | `SshIcon` | `import { SshIcon } from '@vapor-ui/icons'` | | `StarIcon` | `import { StarIcon } from '@vapor-ui/icons'` | | `StopIcon` | `import { StopIcon } from '@vapor-ui/icons'` | | `StorageIcon` | `import { StorageIcon } from '@vapor-ui/icons'` | | `StorybookColorIcon` | `import { StorybookColorIcon } from '@vapor-ui/icons'` | | `StorybookIcon` | `import { StorybookIcon } from '@vapor-ui/icons'` | | `StripeColorIcon` | `import { StripeColorIcon } from '@vapor-ui/icons'` | | `StripeIcon` | `import { StripeIcon } from '@vapor-ui/icons'` | | `StruckIcon` | `import { StruckIcon } from '@vapor-ui/icons'` | | `StudentManagementIcon` | `import { StudentManagementIcon } from '@vapor-ui/icons'` | | `SudanColorIcon` | `import { SudanColorIcon } from '@vapor-ui/icons'` | | `SurinameColorIcon` | `import { SurinameColorIcon } from '@vapor-ui/icons'` | | `SwedenColorIcon` | `import { SwedenColorIcon } from '@vapor-ui/icons'` | | `SwitzerlandColorIcon` | `import { SwitzerlandColorIcon } from '@vapor-ui/icons'` | | `SyllabusIcon` | `import { SyllabusIcon } from '@vapor-ui/icons'` | | `SyriaColorIcon` | `import { SyriaColorIcon } from '@vapor-ui/icons'` | | `TabletIcon` | `import { TabletIcon } from '@vapor-ui/icons'` | | `TaegukColorIcon` | `import { TaegukColorIcon } from '@vapor-ui/icons'` | | `TaegukIcon` | `import { TaegukIcon } from '@vapor-ui/icons'` | | `TajikistanColorIcon` | `import { TajikistanColorIcon } from '@vapor-ui/icons'` | | `TakeoffIcon` | `import { TakeoffIcon } from '@vapor-ui/icons'` | | `TanzaniaColorIcon` | `import { TanzaniaColorIcon } from '@vapor-ui/icons'` | | `TestIcon` | `import { TestIcon } from '@vapor-ui/icons'` | | `ThailandColorIcon` | `import { ThailandColorIcon } from '@vapor-ui/icons'` | | `TimeIcon` | `import { TimeIcon } from '@vapor-ui/icons'` | | `TogoColorIcon` | `import { TogoColorIcon } from '@vapor-ui/icons'` | | `TongaColorIcon` | `import { TongaColorIcon } from '@vapor-ui/icons'` | | `TrashIcon` | `import { TrashIcon } from '@vapor-ui/icons'` | | `TreeCollapseIcon` | `import { TreeCollapseIcon } from '@vapor-ui/icons'` | | `TrelloIcon` | `import { TrelloIcon } from '@vapor-ui/icons'` | | `TrinidadAndTobagoColorIcon` | `import { TrinidadAndTobagoColorIcon } from '@vapor-ui/icons'` | | `TunisiaColorIcon` | `import { TunisiaColorIcon } from '@vapor-ui/icons'` | | `TurkeyColorIcon` | `import { TurkeyColorIcon } from '@vapor-ui/icons'` | | `TurkmenistanColorIcon` | `import { TurkmenistanColorIcon } from '@vapor-ui/icons'` | | `TuvaluColorIcon` | `import { TuvaluColorIcon } from '@vapor-ui/icons'` | | `TwoFileIcon` | `import { TwoFileIcon } from '@vapor-ui/icons'` | | `UgandaColorIcon` | `import { UgandaColorIcon } from '@vapor-ui/icons'` | | `UkraineColorIcon` | `import { UkraineColorIcon } from '@vapor-ui/icons'` | | `UnitedArabEmiratesColorIcon` | `import { UnitedArabEmiratesColorIcon } from '@vapor-ui/icons'` | | `UnitedKingdomColorIcon` | `import { UnitedKingdomColorIcon } from '@vapor-ui/icons'` | | `UnitedStatesColorIcon` | `import { UnitedStatesColorIcon } from '@vapor-ui/icons'` | | `UnlockIcon` | `import { UnlockIcon } from '@vapor-ui/icons'` | | `UploadIcon` | `import { UploadIcon } from '@vapor-ui/icons'` | | `UppercaseIcon` | `import { UppercaseIcon } from '@vapor-ui/icons'` | | `UruguayColorIcon` | `import { UruguayColorIcon } from '@vapor-ui/icons'` | | `UserCheckIcon` | `import { UserCheckIcon } from '@vapor-ui/icons'` | | `UserIcon` | `import { UserIcon } from '@vapor-ui/icons'` | | `UserMoveIcon` | `import { UserMoveIcon } from '@vapor-ui/icons'` | | `UserSearchIcon` | `import { UserSearchIcon } from '@vapor-ui/icons'` | | `UzbekistanColorIcon` | `import { UzbekistanColorIcon } from '@vapor-ui/icons'` | | `VanuatuColorIcon` | `import { VanuatuColorIcon } from '@vapor-ui/icons'` | | `VariableIcon` | `import { VariableIcon } from '@vapor-ui/icons'` | | `VaticanCityColorIcon` | `import { VaticanCityColorIcon } from '@vapor-ui/icons'` | | `VenezuelaColorIcon` | `import { VenezuelaColorIcon } from '@vapor-ui/icons'` | | `VideocamOffIcon` | `import { VideocamOffIcon } from '@vapor-ui/icons'` | | `VideocamOnIcon` | `import { VideocamOnIcon } from '@vapor-ui/icons'` | | `VietnamColorIcon` | `import { VietnamColorIcon } from '@vapor-ui/icons'` | | `ViewModuleIcon` | `import { ViewModuleIcon } from '@vapor-ui/icons'` | | `ViewOffIcon` | `import { ViewOffIcon } from '@vapor-ui/icons'` | | `ViewOnIcon` | `import { ViewOnIcon } from '@vapor-ui/icons'` | | `VscodeColorIcon` | `import { VscodeColorIcon } from '@vapor-ui/icons'` | | `VscodeIcon` | `import { VscodeIcon } from '@vapor-ui/icons'` | | `WarningIcon` | `import { WarningIcon } from '@vapor-ui/icons'` | | `WordMatchIcon` | `import { WordMatchIcon } from '@vapor-ui/icons'` | | `XIcon` | `import { XIcon } from '@vapor-ui/icons'` | | `YemenColorIcon` | `import { YemenColorIcon } from '@vapor-ui/icons'` | | `YoutubeColorIcon` | `import { YoutubeColorIcon } from '@vapor-ui/icons'` | | `YoutubeIcon` | `import { YoutubeIcon } from '@vapor-ui/icons'` | | `ZambiaColorIcon` | `import { ZambiaColorIcon } from '@vapor-ui/icons'` | | `ZimbabweColorIcon` | `import { ZimbabweColorIcon } from '@vapor-ui/icons'` | ## Outline Icons | Icon Name | Import Statement | | -------------------------------------- | ------------------------------------------------------------------------ | | `AccessibilityOutlineIcon` | `import { AccessibilityOutlineIcon } from '@vapor-ui/icons'` | | `AchievementOutlineIcon` | `import { AchievementOutlineIcon } from '@vapor-ui/icons'` | | `AddCartOutlineIcon` | `import { AddCartOutlineIcon } from '@vapor-ui/icons'` | | `AddUserOutlineIcon` | `import { AddUserOutlineIcon } from '@vapor-ui/icons'` | | `AiGoormeeOutlineIcon` | `import { AiGoormeeOutlineIcon } from '@vapor-ui/icons'` | | `AiSmartieOutlineIcon` | `import { AiSmartieOutlineIcon } from '@vapor-ui/icons'` | | `AichatOutlineIcon` | `import { AichatOutlineIcon } from '@vapor-ui/icons'` | | `AirplayOutlineIcon` | `import { AirplayOutlineIcon } from '@vapor-ui/icons'` | | `AlgorithmOutlineIcon` | `import { AlgorithmOutlineIcon } from '@vapor-ui/icons'` | | `AlignCenterOutlineIcon` | `import { AlignCenterOutlineIcon } from '@vapor-ui/icons'` | | `AlignJustifyOutlineIcon` | `import { AlignJustifyOutlineIcon } from '@vapor-ui/icons'` | | `AlignLeftOutlineIcon` | `import { AlignLeftOutlineIcon } from '@vapor-ui/icons'` | | `AlignRightOutlineIcon` | `import { AlignRightOutlineIcon } from '@vapor-ui/icons'` | | `AnalysisOutlineIcon` | `import { AnalysisOutlineIcon } from '@vapor-ui/icons'` | | `ArrowDownOutlineIcon` | `import { ArrowDownOutlineIcon } from '@vapor-ui/icons'` | | `ArrowUpOutlineIcon` | `import { ArrowUpOutlineIcon } from '@vapor-ui/icons'` | | `AssignmentOutlineIcon` | `import { AssignmentOutlineIcon } from '@vapor-ui/icons'` | | `AttachFileOutlineIcon` | `import { AttachFileOutlineIcon } from '@vapor-ui/icons'` | | `AttemptOutlineIcon` | `import { AttemptOutlineIcon } from '@vapor-ui/icons'` | | `AutoCodeOutlineIcon` | `import { AutoCodeOutlineIcon } from '@vapor-ui/icons'` | | `BackPageOutlineIcon` | `import { BackPageOutlineIcon } from '@vapor-ui/icons'` | | `BackUpOutlineIcon` | `import { BackUpOutlineIcon } from '@vapor-ui/icons'` | | `BedOutlineIcon` | `import { BedOutlineIcon } from '@vapor-ui/icons'` | | `BellOffOutlineIcon` | `import { BellOffOutlineIcon } from '@vapor-ui/icons'` | | `BellOnOutlineIcon` | `import { BellOnOutlineIcon } from '@vapor-ui/icons'` | | `BlankOutlineIcon` | `import { BlankOutlineIcon } from '@vapor-ui/icons'` | | `BlockOutlineIcon` | `import { BlockOutlineIcon } from '@vapor-ui/icons'` | | `BoldOutlineIcon` | `import { BoldOutlineIcon } from '@vapor-ui/icons'` | | `BookOutlineIcon` | `import { BookOutlineIcon } from '@vapor-ui/icons'` | | `BookmarkOutlineIcon` | `import { BookmarkOutlineIcon } from '@vapor-ui/icons'` | | `BottomPlayerOutlineIcon` | `import { BottomPlayerOutlineIcon } from '@vapor-ui/icons'` | | `BranchOutlineIcon` | `import { BranchOutlineIcon } from '@vapor-ui/icons'` | | `BuildOutlineIcon` | `import { BuildOutlineIcon } from '@vapor-ui/icons'` | | `BulletlistOutlineIcon` | `import { BulletlistOutlineIcon } from '@vapor-ui/icons'` | | `CafeOutlineIcon` | `import { CafeOutlineIcon } from '@vapor-ui/icons'` | | `CakeOutlineIcon` | `import { CakeOutlineIcon } from '@vapor-ui/icons'` | | `CalculatorOutlineIcon` | `import { CalculatorOutlineIcon } from '@vapor-ui/icons'` | | `CalendarOutlineIcon` | `import { CalendarOutlineIcon } from '@vapor-ui/icons'` | | `CallOutlineIcon` | `import { CallOutlineIcon } from '@vapor-ui/icons'` | | `CameraOutlineIcon` | `import { CameraOutlineIcon } from '@vapor-ui/icons'` | | `CampOutlineIcon` | `import { CampOutlineIcon } from '@vapor-ui/icons'` | | `CaptionOutlineIcon` | `import { CaptionOutlineIcon } from '@vapor-ui/icons'` | | `CarOutlineIcon` | `import { CarOutlineIcon } from '@vapor-ui/icons'` | | `CardsOutlineIcon` | `import { CardsOutlineIcon } from '@vapor-ui/icons'` | | `CertificateOutlineIcon` | `import { CertificateOutlineIcon } from '@vapor-ui/icons'` | | `ChapterOutlineIcon` | `import { ChapterOutlineIcon } from '@vapor-ui/icons'` | | `ChartOutlineIcon` | `import { ChartOutlineIcon } from '@vapor-ui/icons'` | | `ChartPieOutlineIcon` | `import { ChartPieOutlineIcon } from '@vapor-ui/icons'` | | `CheckCartOutlineIcon` | `import { CheckCartOutlineIcon } from '@vapor-ui/icons'` | | `CheckCircleOutlineIcon` | `import { CheckCircleOutlineIcon } from '@vapor-ui/icons'` | | `ChecklistOutlineIcon` | `import { ChecklistOutlineIcon } from '@vapor-ui/icons'` | | `ChevronDoubleLeftOutlineIcon` | `import { ChevronDoubleLeftOutlineIcon } from '@vapor-ui/icons'` | | `ChevronDoubleRightOutlineIcon` | `import { ChevronDoubleRightOutlineIcon } from '@vapor-ui/icons'` | | `ChevronDownOutlineIcon` | `import { ChevronDownOutlineIcon } from '@vapor-ui/icons'` | | `ChevronLeftOutlineIcon` | `import { ChevronLeftOutlineIcon } from '@vapor-ui/icons'` | | `ChevronRightOutlineIcon` | `import { ChevronRightOutlineIcon } from '@vapor-ui/icons'` | | `ChevronUpOutlineIcon` | `import { ChevronUpOutlineIcon } from '@vapor-ui/icons'` | | `CloseOutlineIcon` | `import { CloseOutlineIcon } from '@vapor-ui/icons'` | | `CodeBlockOutlineIcon` | `import { CodeBlockOutlineIcon } from '@vapor-ui/icons'` | | `CollaborationOutlineIcon` | `import { CollaborationOutlineIcon } from '@vapor-ui/icons'` | | `CollapseOutlineIcon` | `import { CollapseOutlineIcon } from '@vapor-ui/icons'` | | `CommitOutlineIcon` | `import { CommitOutlineIcon } from '@vapor-ui/icons'` | | `ConfirmOutlineIcon` | `import { ConfirmOutlineIcon } from '@vapor-ui/icons'` | | `ContainerOutlineIcon` | `import { ContainerOutlineIcon } from '@vapor-ui/icons'` | | `ContainerRunOutlineIcon` | `import { ContainerRunOutlineIcon } from '@vapor-ui/icons'` | | `ContainerShareOutlineIcon` | `import { ContainerShareOutlineIcon } from '@vapor-ui/icons'` | | `ContainerStopOutlineIcon` | `import { ContainerStopOutlineIcon } from '@vapor-ui/icons'` | | `ControlCommonOutlineIcon` | `import { ControlCommonOutlineIcon } from '@vapor-ui/icons'` | | `CopyAsMarkdownOutlineIcon` | `import { CopyAsMarkdownOutlineIcon } from '@vapor-ui/icons'` | | `CopyOutlineIcon` | `import { CopyOutlineIcon } from '@vapor-ui/icons'` | | `CorrectOutlineIcon` | `import { CorrectOutlineIcon } from '@vapor-ui/icons'` | | `CouponOutlineIcon` | `import { CouponOutlineIcon } from '@vapor-ui/icons'` | | `CourseOutlineIcon` | `import { CourseOutlineIcon } from '@vapor-ui/icons'` | | `CpuOutlineIcon` | `import { CpuOutlineIcon } from '@vapor-ui/icons'` | | `CreateBranchOutlineIcon` | `import { CreateBranchOutlineIcon } from '@vapor-ui/icons'` | | `CreditCardOutlineIcon` | `import { CreditCardOutlineIcon } from '@vapor-ui/icons'` | | `DarkOutlineIcon` | `import { DarkOutlineIcon } from '@vapor-ui/icons'` | | `DashboardOutlineIcon` | `import { DashboardOutlineIcon } from '@vapor-ui/icons'` | | `DatabaseOutlineIcon` | `import { DatabaseOutlineIcon } from '@vapor-ui/icons'` | | `DebugOutlineIcon` | `import { DebugOutlineIcon } from '@vapor-ui/icons'` | | `DeployOutlineIcon` | `import { DeployOutlineIcon } from '@vapor-ui/icons'` | | `DeployPushOutlineIcon` | `import { DeployPushOutlineIcon } from '@vapor-ui/icons'` | | `DetailViewOutlineIcon` | `import { DetailViewOutlineIcon } from '@vapor-ui/icons'` | | `DiscOutlineIcon` | `import { DiscOutlineIcon } from '@vapor-ui/icons'` | | `DiscardOutlineIcon` | `import { DiscardOutlineIcon } from '@vapor-ui/icons'` | | `DiscussionOutlineIcon` | `import { DiscussionOutlineIcon } from '@vapor-ui/icons'` | | `DislikeOutlineIcon` | `import { DislikeOutlineIcon } from '@vapor-ui/icons'` | | `DislikeThumbOutlineIcon` | `import { DislikeThumbOutlineIcon } from '@vapor-ui/icons'` | | `DividerOutlineIcon` | `import { DividerOutlineIcon } from '@vapor-ui/icons'` | | `DocktoBottomOutlineIcon` | `import { DocktoBottomOutlineIcon } from '@vapor-ui/icons'` | | `DocumentViewerOutlineIcon` | `import { DocumentViewerOutlineIcon } from '@vapor-ui/icons'` | | `DollarOutlineIcon` | `import { DollarOutlineIcon } from '@vapor-ui/icons'` | | `DownloadOutlineIcon` | `import { DownloadOutlineIcon } from '@vapor-ui/icons'` | | `EditOutlineIcon` | `import { EditOutlineIcon } from '@vapor-ui/icons'` | | `EnterOutlineIcon` | `import { EnterOutlineIcon } from '@vapor-ui/icons'` | | `EqualOutlineIcon` | `import { EqualOutlineIcon } from '@vapor-ui/icons'` | | `EraserOutlineIcon` | `import { EraserOutlineIcon } from '@vapor-ui/icons'` | | `ErrorCircleOutlineIcon` | `import { ErrorCircleOutlineIcon } from '@vapor-ui/icons'` | | `ExamListOutlineIcon` | `import { ExamListOutlineIcon } from '@vapor-ui/icons'` | | `ExamOutlineIcon` | `import { ExamOutlineIcon } from '@vapor-ui/icons'` | | `ExamReportOutlineIcon` | `import { ExamReportOutlineIcon } from '@vapor-ui/icons'` | | `ExpandOutlineIcon` | `import { ExpandOutlineIcon } from '@vapor-ui/icons'` | | `ExploreOutlineIcon` | `import { ExploreOutlineIcon } from '@vapor-ui/icons'` | | `ExportOutlineIcon` | `import { ExportOutlineIcon } from '@vapor-ui/icons'` | | `FileAddOutlineIcon` | `import { FileAddOutlineIcon } from '@vapor-ui/icons'` | | `FileDeleteOutlineIcon` | `import { FileDeleteOutlineIcon } from '@vapor-ui/icons'` | | `FileEditOutlineIcon` | `import { FileEditOutlineIcon } from '@vapor-ui/icons'` | | `FileNewOutlineIcon` | `import { FileNewOutlineIcon } from '@vapor-ui/icons'` | | `FileOutlineIcon` | `import { FileOutlineIcon } from '@vapor-ui/icons'` | | `FilterOutlineIcon` | `import { FilterOutlineIcon } from '@vapor-ui/icons'` | | `FlagOutlineIcon` | `import { FlagOutlineIcon } from '@vapor-ui/icons'` | | `FoldOutlineIcon` | `import { FoldOutlineIcon } from '@vapor-ui/icons'` | | `FolderNewOutlineIcon` | `import { FolderNewOutlineIcon } from '@vapor-ui/icons'` | | `FolderOutlineIcon` | `import { FolderOutlineIcon } from '@vapor-ui/icons'` | | `FolderSearchOutlineIcon` | `import { FolderSearchOutlineIcon } from '@vapor-ui/icons'` | | `ForkOutlineIcon` | `import { ForkOutlineIcon } from '@vapor-ui/icons'` | | `FormatColorTextOutlineIcon` | `import { FormatColorTextOutlineIcon } from '@vapor-ui/icons'` | | `ForwardPageOutlineIcon` | `import { ForwardPageOutlineIcon } from '@vapor-ui/icons'` | | `FunctionOutlineIcon` | `import { FunctionOutlineIcon } from '@vapor-ui/icons'` | | `FunctionsOutlineIcon` | `import { FunctionsOutlineIcon } from '@vapor-ui/icons'` | | `GameOutlineIcon` | `import { GameOutlineIcon } from '@vapor-ui/icons'` | | `GiftOutlineIcon` | `import { GiftOutlineIcon } from '@vapor-ui/icons'` | | `GitMergeOutlineIcon` | `import { GitMergeOutlineIcon } from '@vapor-ui/icons'` | | `GlobalOutlineIcon` | `import { GlobalOutlineIcon } from '@vapor-ui/icons'` | | `GoogleDrawingOutlineIcon` | `import { GoogleDrawingOutlineIcon } from '@vapor-ui/icons'` | | `GooglePresentationOutlineIcon` | `import { GooglePresentationOutlineIcon } from '@vapor-ui/icons'` | | `GoogleSpreadsheetOutlineIcon` | `import { GoogleSpreadsheetOutlineIcon } from '@vapor-ui/icons'` | | `GroupOutlineIcon` | `import { GroupOutlineIcon } from '@vapor-ui/icons'` | | `HardBreakOutlineIcon` | `import { HardBreakOutlineIcon } from '@vapor-ui/icons'` | | `Heading1OutlineIcon` | `import { Heading1OutlineIcon } from '@vapor-ui/icons'` | | `Heading2OutlineIcon` | `import { Heading2OutlineIcon } from '@vapor-ui/icons'` | | `Heading3OutlineIcon` | `import { Heading3OutlineIcon } from '@vapor-ui/icons'` | | `Heading4OutlineIcon` | `import { Heading4OutlineIcon } from '@vapor-ui/icons'` | | `HeartOutlineIcon` | `import { HeartOutlineIcon } from '@vapor-ui/icons'` | | `HelpCircleOutlineIcon` | `import { HelpCircleOutlineIcon } from '@vapor-ui/icons'` | | `HighlightViewOutlineIcon` | `import { HighlightViewOutlineIcon } from '@vapor-ui/icons'` | | `HistoryOutlineIcon` | `import { HistoryOutlineIcon } from '@vapor-ui/icons'` | | `HomeOutlineIcon` | `import { HomeOutlineIcon } from '@vapor-ui/icons'` | | `IdCardOutlineIcon` | `import { IdCardOutlineIcon } from '@vapor-ui/icons'` | | `ImageOutlineIcon` | `import { ImageOutlineIcon } from '@vapor-ui/icons'` | | `ImagePackOutlineIcon` | `import { ImagePackOutlineIcon } from '@vapor-ui/icons'` | | `ImageToContainerOutlineIcon` | `import { ImageToContainerOutlineIcon } from '@vapor-ui/icons'` | | `ImportOutlineIcon` | `import { ImportOutlineIcon } from '@vapor-ui/icons'` | | `InOutlineIcon` | `import { InOutlineIcon } from '@vapor-ui/icons'` | | `IndentDecreaseOutlineIcon` | `import { IndentDecreaseOutlineIcon } from '@vapor-ui/icons'` | | `IndentIncreaseOutlineIcon` | `import { IndentIncreaseOutlineIcon } from '@vapor-ui/icons'` | | `InfiniteOutlineIcon` | `import { InfiniteOutlineIcon } from '@vapor-ui/icons'` | | `InfoCircleOutlineIcon` | `import { InfoCircleOutlineIcon } from '@vapor-ui/icons'` | | `InputSettingOutlineIcon` | `import { InputSettingOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseEnumOutlineIcon` | `import { IntelliSenseEnumOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseEventOutlineIcon` | `import { IntelliSenseEventOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseFieldOutlineIcon` | `import { IntelliSenseFieldOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseModuleOutlineIcon` | `import { IntelliSenseModuleOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSensePropertyOutlineIcon` | `import { IntelliSensePropertyOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseReferenceOutlineIcon` | `import { IntelliSenseReferenceOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseSnippetOutlineIcon` | `import { IntelliSenseSnippetOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseTypeParameterOutlineIcon` | `import { IntelliSenseTypeParameterOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseUnitOutlineIcon` | `import { IntelliSenseUnitOutlineIcon } from '@vapor-ui/icons'` | | `IntelliSenseVariableOutlineIcon` | `import { IntelliSenseVariableOutlineIcon } from '@vapor-ui/icons'` | | `KeyboardOutlineIcon` | `import { KeyboardOutlineIcon } from '@vapor-ui/icons'` | | `KidOutlineIcon` | `import { KidOutlineIcon } from '@vapor-ui/icons'` | | `LightOutlineIcon` | `import { LightOutlineIcon } from '@vapor-ui/icons'` | | `LightbulbOutlineIcon` | `import { LightbulbOutlineIcon } from '@vapor-ui/icons'` | | `LightningOutlineIcon` | `import { LightningOutlineIcon } from '@vapor-ui/icons'` | | `LikeOutlineIcon` | `import { LikeOutlineIcon } from '@vapor-ui/icons'` | | `LikeThumbOutlineIcon` | `import { LikeThumbOutlineIcon } from '@vapor-ui/icons'` | | `LineSpacingOutlineIcon` | `import { LineSpacingOutlineIcon } from '@vapor-ui/icons'` | | `LineStyleOutlineIcon` | `import { LineStyleOutlineIcon } from '@vapor-ui/icons'` | | `LinearScaleOutlineIcon` | `import { LinearScaleOutlineIcon } from '@vapor-ui/icons'` | | `LinkOffOutlineIcon` | `import { LinkOffOutlineIcon } from '@vapor-ui/icons'` | | `LinkOutlineIcon` | `import { LinkOutlineIcon } from '@vapor-ui/icons'` | | `LiveLessonOutlineIcon` | `import { LiveLessonOutlineIcon } from '@vapor-ui/icons'` | | `LocationOutlineIcon` | `import { LocationOutlineIcon } from '@vapor-ui/icons'` | | `LockOutlineIcon` | `import { LockOutlineIcon } from '@vapor-ui/icons'` | | `LongTextOutlineIcon` | `import { LongTextOutlineIcon } from '@vapor-ui/icons'` | | `MagicWandOutlineIcon` | `import { MagicWandOutlineIcon } from '@vapor-ui/icons'` | | `MailOutlineIcon` | `import { MailOutlineIcon } from '@vapor-ui/icons'` | | `ManagementOutlineIcon` | `import { ManagementOutlineIcon } from '@vapor-ui/icons'` | | `MarkModeOutlineIcon` | `import { MarkModeOutlineIcon } from '@vapor-ui/icons'` | | `MarkdownOutlineIcon` | `import { MarkdownOutlineIcon } from '@vapor-ui/icons'` | | `MemoOutlineIcon` | `import { MemoOutlineIcon } from '@vapor-ui/icons'` | | `MenuOutlineIcon` | `import { MenuOutlineIcon } from '@vapor-ui/icons'` | | `MergeUpOutlineIcon` | `import { MergeUpOutlineIcon } from '@vapor-ui/icons'` | | `MessageOutlineIcon` | `import { MessageOutlineIcon } from '@vapor-ui/icons'` | | `MethodOutlineIcon` | `import { MethodOutlineIcon } from '@vapor-ui/icons'` | | `MicOffOutlineIcon` | `import { MicOffOutlineIcon } from '@vapor-ui/icons'` | | `MicOnOutlineIcon` | `import { MicOnOutlineIcon } from '@vapor-ui/icons'` | | `MinusBoxOutlineIcon` | `import { MinusBoxOutlineIcon } from '@vapor-ui/icons'` | | `MinusOutlineIcon` | `import { MinusOutlineIcon } from '@vapor-ui/icons'` | | `MoreCommonOutlineIcon` | `import { MoreCommonOutlineIcon } from '@vapor-ui/icons'` | | `MovieOutlineIcon` | `import { MovieOutlineIcon } from '@vapor-ui/icons'` | | `NetfficeOutlineIcon` | `import { NetfficeOutlineIcon } from '@vapor-ui/icons'` | | `NetworkOutlineIcon` | `import { NetworkOutlineIcon } from '@vapor-ui/icons'` | | `NextOutlineIcon` | `import { NextOutlineIcon } from '@vapor-ui/icons'` | | `NoImageOutlineIcon` | `import { NoImageOutlineIcon } from '@vapor-ui/icons'` | | `NoUserOutlineIcon` | `import { NoUserOutlineIcon } from '@vapor-ui/icons'` | | `NoticeBoardOutlineIcon` | `import { NoticeBoardOutlineIcon } from '@vapor-ui/icons'` | | `NoticeCircleOutlineIcon` | `import { NoticeCircleOutlineIcon } from '@vapor-ui/icons'` | | `NumberlistOutlineIcon` | `import { NumberlistOutlineIcon } from '@vapor-ui/icons'` | | `OpenFileOutlineIcon` | `import { OpenFileOutlineIcon } from '@vapor-ui/icons'` | | `OpenFolderOutlineIcon` | `import { OpenFolderOutlineIcon } from '@vapor-ui/icons'` | | `OpenInNewOutlineIcon` | `import { OpenInNewOutlineIcon } from '@vapor-ui/icons'` | | `OutOutlineIcon` | `import { OutOutlineIcon } from '@vapor-ui/icons'` | | `PandasOutlineIcon` | `import { PandasOutlineIcon } from '@vapor-ui/icons'` | | `PanelOpenOutlineIcon` | `import { PanelOpenOutlineIcon } from '@vapor-ui/icons'` | | `PauseOutlineIcon` | `import { PauseOutlineIcon } from '@vapor-ui/icons'` | | `PcOutlineIcon` | `import { PcOutlineIcon } from '@vapor-ui/icons'` | | `PdfOutlineIcon` | `import { PdfOutlineIcon } from '@vapor-ui/icons'` | | `PhoneOutlineIcon` | `import { PhoneOutlineIcon } from '@vapor-ui/icons'` | | `PinSetOutlineIcon` | `import { PinSetOutlineIcon } from '@vapor-ui/icons'` | | `PlansOutlineIcon` | `import { PlansOutlineIcon } from '@vapor-ui/icons'` | | `PlayOutlineIcon` | `import { PlayOutlineIcon } from '@vapor-ui/icons'` | | `PlaylistOutlineIcon` | `import { PlaylistOutlineIcon } from '@vapor-ui/icons'` | | `PlusBoxOutlineIcon` | `import { PlusBoxOutlineIcon } from '@vapor-ui/icons'` | | `PlusOutlineIcon` | `import { PlusOutlineIcon } from '@vapor-ui/icons'` | | `PortforwardingOutlineIcon` | `import { PortforwardingOutlineIcon } from '@vapor-ui/icons'` | | `PreOutlineIcon` | `import { PreOutlineIcon } from '@vapor-ui/icons'` | | `PresentScreenOutlineIcon` | `import { PresentScreenOutlineIcon } from '@vapor-ui/icons'` | | `PresetOutlineIcon` | `import { PresetOutlineIcon } from '@vapor-ui/icons'` | | `PreviewOutlineIcon` | `import { PreviewOutlineIcon } from '@vapor-ui/icons'` | | `PriceOutlineIcon` | `import { PriceOutlineIcon } from '@vapor-ui/icons'` | | `PrintOutlineIcon` | `import { PrintOutlineIcon } from '@vapor-ui/icons'` | | `ProjectOutlineIcon` | `import { ProjectOutlineIcon } from '@vapor-ui/icons'` | | `ProjectSettingOutlineIcon` | `import { ProjectSettingOutlineIcon } from '@vapor-ui/icons'` | | `PsychologyOutlineIcon` | `import { PsychologyOutlineIcon } from '@vapor-ui/icons'` | | `PublishOutlineIcon` | `import { PublishOutlineIcon } from '@vapor-ui/icons'` | | `PullOutlineIcon` | `import { PullOutlineIcon } from '@vapor-ui/icons'` | | `QnAOutlineIcon` | `import { QnAOutlineIcon } from '@vapor-ui/icons'` | | `QrcodeOutlineIcon` | `import { QrcodeOutlineIcon } from '@vapor-ui/icons'` | | `QuoteOutlineIcon` | `import { QuoteOutlineIcon } from '@vapor-ui/icons'` | | `ReferenceOutlineIcon` | `import { ReferenceOutlineIcon } from '@vapor-ui/icons'` | | `RefreshOutlineIcon` | `import { RefreshOutlineIcon } from '@vapor-ui/icons'` | | `RegexOutlineIcon` | `import { RegexOutlineIcon } from '@vapor-ui/icons'` | | `ReloadOutlineIcon` | `import { ReloadOutlineIcon } from '@vapor-ui/icons'` | | `RemoteOffOutlineIcon` | `import { RemoteOffOutlineIcon } from '@vapor-ui/icons'` | | `RemoteOutlineIcon` | `import { RemoteOutlineIcon } from '@vapor-ui/icons'` | | `ReplyOutlineIcon` | `import { ReplyOutlineIcon } from '@vapor-ui/icons'` | | `RestaurantOutlineIcon` | `import { RestaurantOutlineIcon } from '@vapor-ui/icons'` | | `ResultManagementOutlineIcon` | `import { ResultManagementOutlineIcon } from '@vapor-ui/icons'` | | `RouteOutlineIcon` | `import { RouteOutlineIcon } from '@vapor-ui/icons'` | | `RunOutlineIcon` | `import { RunOutlineIcon } from '@vapor-ui/icons'` | | `SaveAsOutlineIcon` | `import { SaveAsOutlineIcon } from '@vapor-ui/icons'` | | `SaveOutlineIcon` | `import { SaveOutlineIcon } from '@vapor-ui/icons'` | | `SavingOutlineIcon` | `import { SavingOutlineIcon } from '@vapor-ui/icons'` | | `SchoolOutlineIcon` | `import { SchoolOutlineIcon } from '@vapor-ui/icons'` | | `SearchOutlineIcon` | `import { SearchOutlineIcon } from '@vapor-ui/icons'` | | `SendOutlineIcon` | `import { SendOutlineIcon } from '@vapor-ui/icons'` | | `SettingOutlineIcon` | `import { SettingOutlineIcon } from '@vapor-ui/icons'` | | `ShareOutlineIcon` | `import { ShareOutlineIcon } from '@vapor-ui/icons'` | | `ShoppingCartOutlineIcon` | `import { ShoppingCartOutlineIcon } from '@vapor-ui/icons'` | | `ShortTextOutlineIcon` | `import { ShortTextOutlineIcon } from '@vapor-ui/icons'` | | `ShortcutOutlineIcon` | `import { ShortcutOutlineIcon } from '@vapor-ui/icons'` | | `SideNavOutlineIcon` | `import { SideNavOutlineIcon } from '@vapor-ui/icons'` | | `SignalPowerOutlineIcon` | `import { SignalPowerOutlineIcon } from '@vapor-ui/icons'` | | `SlashOutlineIcon` | `import { SlashOutlineIcon } from '@vapor-ui/icons'` | | `SoundOffOutlineIcon` | `import { SoundOffOutlineIcon } from '@vapor-ui/icons'` | | `SoundOnOutlineIcon` | `import { SoundOnOutlineIcon } from '@vapor-ui/icons'` | | `SpinnerOutlineIcon` | `import { SpinnerOutlineIcon } from '@vapor-ui/icons'` | | `SplitHorizontalOutlineIcon` | `import { SplitHorizontalOutlineIcon } from '@vapor-ui/icons'` | | `SplitVerticalOutlineIcon` | `import { SplitVerticalOutlineIcon } from '@vapor-ui/icons'` | | `StarOutlineIcon` | `import { StarOutlineIcon } from '@vapor-ui/icons'` | | `StepInOutlineIcon` | `import { StepInOutlineIcon } from '@vapor-ui/icons'` | | `StepOutOutlineIcon` | `import { StepOutOutlineIcon } from '@vapor-ui/icons'` | | `StepOverOutlineIcon` | `import { StepOverOutlineIcon } from '@vapor-ui/icons'` | | `StopOutlineIcon` | `import { StopOutlineIcon } from '@vapor-ui/icons'` | | `StrikeOutlineIcon` | `import { StrikeOutlineIcon } from '@vapor-ui/icons'` | | `StruckOutlineIcon` | `import { StruckOutlineIcon } from '@vapor-ui/icons'` | | `StudentManagementOutlineIcon` | `import { StudentManagementOutlineIcon } from '@vapor-ui/icons'` | | `SyllabusOutlineIcon` | `import { SyllabusOutlineIcon } from '@vapor-ui/icons'` | | `TableFilterOutlineIcon` | `import { TableFilterOutlineIcon } from '@vapor-ui/icons'` | | `TableOutlineIcon` | `import { TableOutlineIcon } from '@vapor-ui/icons'` | | `TabletOutlineIcon` | `import { TabletOutlineIcon } from '@vapor-ui/icons'` | | `TerminalConnectOutlineIcon` | `import { TerminalConnectOutlineIcon } from '@vapor-ui/icons'` | | `TerminalOutlineIcon` | `import { TerminalOutlineIcon } from '@vapor-ui/icons'` | | `TerminalWindowOutlineIcon` | `import { TerminalWindowOutlineIcon } from '@vapor-ui/icons'` | | `TestOutlineIcon` | `import { TestOutlineIcon } from '@vapor-ui/icons'` | | `TextColorOutlineIcon` | `import { TextColorOutlineIcon } from '@vapor-ui/icons'` | | `TextOutlineIcon` | `import { TextOutlineIcon } from '@vapor-ui/icons'` | | `TextScanOutlineIcon` | `import { TextScanOutlineIcon } from '@vapor-ui/icons'` | | `TimeOutlineIcon` | `import { TimeOutlineIcon } from '@vapor-ui/icons'` | | `TransferOutlineIcon` | `import { TransferOutlineIcon } from '@vapor-ui/icons'` | | `TranslateOutlineIcon` | `import { TranslateOutlineIcon } from '@vapor-ui/icons'` | | `TrashOutlineIcon` | `import { TrashOutlineIcon } from '@vapor-ui/icons'` | | `TriangleOutlineIcon` | `import { TriangleOutlineIcon } from '@vapor-ui/icons'` | | `UnderlineOutlineIcon` | `import { UnderlineOutlineIcon } from '@vapor-ui/icons'` | | `UndoOutlineIcon` | `import { UndoOutlineIcon } from '@vapor-ui/icons'` | | `UnlockOutlineIcon` | `import { UnlockOutlineIcon } from '@vapor-ui/icons'` | | `UploadOutlineIcon` | `import { UploadOutlineIcon } from '@vapor-ui/icons'` | | `UserCheckOutlineIcon` | `import { UserCheckOutlineIcon } from '@vapor-ui/icons'` | | `UserMoveOutlineIcon` | `import { UserMoveOutlineIcon } from '@vapor-ui/icons'` | | `UserOutlineIcon` | `import { UserOutlineIcon } from '@vapor-ui/icons'` | | `UserSearchOutlineIcon` | `import { UserSearchOutlineIcon } from '@vapor-ui/icons'` | | `VideocamOffOutlineIcon` | `import { VideocamOffOutlineIcon } from '@vapor-ui/icons'` | | `VideocamOnOutlineIcon` | `import { VideocamOnOutlineIcon } from '@vapor-ui/icons'` | | `ViewExpandOutlineIcon` | `import { ViewExpandOutlineIcon } from '@vapor-ui/icons'` | | `ViewModuleOutlineIcon` | `import { ViewModuleOutlineIcon } from '@vapor-ui/icons'` | | `ViewOffOutlineIcon` | `import { ViewOffOutlineIcon } from '@vapor-ui/icons'` | | `ViewOnOutlineIcon` | `import { ViewOnOutlineIcon } from '@vapor-ui/icons'` | | `ViewShrinkOutlineIcon` | `import { ViewShrinkOutlineIcon } from '@vapor-ui/icons'` | | `WarningOutlineIcon` | `import { WarningOutlineIcon } from '@vapor-ui/icons'` | | `WordSearchOutlineIcon` | `import { WordSearchOutlineIcon } from '@vapor-ui/icons'` | | `ZoomInOutlineIcon` | `import { ZoomInOutlineIcon } from '@vapor-ui/icons'` | | `ZoomOutOutlineIcon` | `import { ZoomOutOutlineIcon } from '@vapor-ui/icons'` | # All Components URL: /docs/components Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/index.mdx 빠른 개발과 일관된 디자인을 위한 Vapor UI 디자인 시스템을 살펴보세요. *** ## Components # Introduction URL: /docs/getting-started Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/getting-started/index.mdx 빠른 개발과 일관된 디자인을 위한 Vapor UI 디자인 시스템을 살펴보세요. ## Vapor UI 소개 Vapor UI는 개발자 경험과 디자인 일관성을 모두 만족시키는 React 컴포넌트 라이브러리입니다. 구름에서 개발한 세 번째 디자인 시스템으로, 실제 프로덕션에서 검증된 컴포넌트들을 제공합니다. ## 핵심 기능 * **모듈화된 구조**: 필요한 패키지만 선택적으로 설치하여 번들 크기를 최적화합니다. * **TypeScript 지원**: 모든 컴포넌트에 타입 정의가 포함되어 자동 완성과 타입 검사를 지원합니다. * **접근성 내장**: WCAG 2.1 AA 수준의 웹 접근성을 기본으로 제공합니다. * **Tailwind CSS 통합**: Tailwind 유틸리티 클래스로 컴포넌트를 빠르게 커스터마이징할 수 있습니다. * **다크 모드**: 라이트/다크 테마 자동 전환 시스템을 제공합니다. ## 적합한 프로젝트 Vapor UI는 다음과 같은 프로젝트에서 효과적으로 활용할 수 있습니다. * 빠른 프로토타이핑이 필요한 스타트업과 신규 프로젝트 * 일관된 디자인 시스템을 구축하려는 중대형 팀 * 접근성을 중요시하는 공공 서비스나 글로벌 서비스 * TypeScript 환경의 모던 React 프로젝트 * 디자인과 개발 간 협업이 중요한 조직 # Codemod URL: /docs/releases/codemod Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/releases/codemod.md @vapor-ui/codemod 패키지의 릴리즈 노트입니다. # @vapor-ui/codemod ## 1.1.0 ### Node * Require Node.js 24 or later ([#676](https://github.com/goorm-dev/vapor-ui/pull/676)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ## 1.0.0 ### Codemod * Add v1/migrate transform for @vapor-ui/core v1.0.0 migration ([#454](https://github.com/goorm-dev/vapor-ui/pull/454)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * `trackAnchor` → `disableAnchorTracking` (boolean inversion) * `loop` → `loopFocus` (Menu, Tabs) * Move `openOnHover`, `delay`, `closeDelay` from Root to Trigger (Tooltip, Preview Card) * `hoverable` → `disableHoverablePopup` (Tooltip only, boolean inversion) ## 1.0.0-beta.7 ### CLI * Add Tabs, Text, Textinput transform ([#319](https://github.com/goorm-dev/vapor-ui/pull/319)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * Add Dropdown, IconButton, Nav transformer ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * add avatar, breadcrumb, card transform ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * Add Popover, RadioGroup, Switch Transform ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * Add codemod for icon packages name import ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * add codemod cli packages ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * add cli options ([#351](https://github.com/goorm-dev/vapor-ui/pull/351)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * add button, badge, alert component color props to colorPalette ([#362](https://github.com/goorm-dev/vapor-ui/pull/362)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ## 1.0.0-beta.6 ### CLI * add checkbox, collapsible, dialog transform ([#316](https://github.com/goorm-dev/vapor-ui/pull/316)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * add avatar, breadcrumb, card transform ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * add codemod cli packages ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ## 1.0.0-beta.5 ### CLI * Add codemod for icon packages name import ([#317](https://github.com/goorm-dev/vapor-ui/pull/317)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! # Color Generator URL: /docs/releases/color-generator Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/releases/color-generator.md @vapor-ui/color-generator 패키지의 릴리즈 노트입니다. # @vapor-ui/color-generator ## 1.0.0-beta.8 ### Tokens * **BREAKING CHANGE**: rename `color-background-canvas` token to `color-canvas` ([#378](https://github.com/goorm-dev/vapor-ui/pull/378)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! The canvas background token has been renamed for better semantic clarity and consistency: * Token name: `color-background-canvas` → `color-canvas` * CSS variable: `--vapor-color-background-canvas` → `--vapor-color-canvas` **Migration required:** * Update all references from `color-background-canvas` to `color-canvas` * Replace CSS variables from `--vapor-color-background-canvas` to `--vapor-color-canvas` ## 1.0.0-beta.7 ### Color Generator * add color-border-normal semantic token that dynamically adapts to background color customization (light: 100 step, dark: 300 step) ([#370](https://github.com/goorm-dev/vapor-ui/pull/370)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ## 1.0.0-beta.6 ### Etc. * feat: update color generator & color palette ([#337](https://github.com/goorm-dev/vapor-ui/pull/337)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ## 1.0.0-beta.5 ### Etc. * feat: create @vapor-ui/color-generator & @vapor-ui/css-generator ([#234](https://github.com/goorm-dev/vapor-ui/pull/234)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * feat: update color tokens ([#261](https://github.com/goorm-dev/vapor-ui/pull/261)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! # Core URL: /docs/releases/core Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/releases/core.md @vapor-ui/core 패키지의 릴리즈 노트입니다. # @vapor-ui/core ## 1.6.0 ### Alertdialog * add AlertDialog.Header ([#725](https://github.com/goorm-dev/vapor-ui/pull/725)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Button * apply the light interaction layer to the `ghost` variant of `Button` and `IconButton` to match the design ([#747](https://github.com/goorm-dev/vapor-ui/pull/747)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Core * align component backgrounds with the canvas token hierarchy and expose `bg-canvas-inverse` in sprinkles ([#698](https://github.com/goorm-dev/vapor-ui/pull/698)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * Extract shared arrow positioning logic from `NavigationMenu`, `Popover`, and `Tooltip` into a `useArrowPosition` hook. Also bump the default `sideOffset` of these three primitives from `8` to `10`. ([#758](https://github.com/goorm-dev/vapor-ui/pull/758)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Deps * update `@base-ui/react` to 1.8.0 — support `keepMounted` on `Avatar` with stacked image/fallback styles, accept functional updater in Toast `update` ([#729](https://github.com/goorm-dev/vapor-ui/pull/729)) - Thanks [@renovate](https://github.com/apps/renovate)! ### Dialog * align `Dialog` header/body/footer padding with design — remove the fixed `Dialog.Header` height (56px) and use padding instead (top 24 / Header→Body 20 / Body→Footer 20 / bottom 24). Vertical spacing of existing dialogs will change. ([#760](https://github.com/goorm-dev/vapor-ui/pull/760)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Meter * add new `Meter` component ([#700](https://github.com/goorm-dev/vapor-ui/pull/700)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Progressbar * add new `ProgressBar` component ([#702](https://github.com/goorm-dev/vapor-ui/pull/702)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Radio Group * add RadioGroup.RequiredSymbol ([#753](https://github.com/goorm-dev/vapor-ui/pull/753)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Spinner * respect `prefers-reduced-motion` and hide decorative svg from assistive technology ([#689](https://github.com/goorm-dev/vapor-ui/pull/689)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Typography * fix the code font family name to `"Fira Code"` and apply it to the `code1` / `code2` typography styles ([#748](https://github.com/goorm-dev/vapor-ui/pull/748)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Etc. * add data-slots for all components ([#703](https://github.com/goorm-dev/vapor-ui/pull/703)) - Thanks [@noahchoii](https://github.com/noahchoii)! * add new `AlertDialog` components ([#704](https://github.com/goorm-dev/vapor-ui/pull/704)) - Thanks [@noahchoii](https://github.com/noahchoii)! * apply `canvas-inverse` tokens to the tooltip/toast component. ([#696](https://github.com/goorm-dev/vapor-ui/pull/696)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Updated Dependencies * @vapor-ui/icons\@1.3.1 ## 1.5.1 ### Css * migrate V2 foundations ([#690](https://github.com/goorm-dev/vapor-ui/pull/690)) - Thanks [@noahchoii](https://github.com/noahchoii)! ## 1.5.0 ### Css * **Breaking Change**: inverse color tokens have been changed. In light mode, inverse is dark, in dark mode, inverse is light. ([#644](https://github.com/goorm-dev/vapor-ui/pull/644)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Toggle * add new `ToggleGroup` component ([#628](https://github.com/goorm-dev/vapor-ui/pull/628)) - Thanks [@noahchoii](https://github.com/noahchoii)! * add new `Toggle` component ([#628](https://github.com/goorm-dev/vapor-ui/pull/628)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Toolbar * add new `Toolbar` component ([#643](https://github.com/goorm-dev/vapor-ui/pull/643)) - Thanks [@noahchoii](https://github.com/noahchoii)! ## 1.4.0 ### Sheet * Add `Sheet.ResizeHandle` for edge drag-and-keyboard resizing. ([#634](https://github.com/goorm-dev/vapor-ui/pull/634)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Checkbox * propagate `invalid` state to indicator element ([#618](https://github.com/goorm-dev/vapor-ui/pull/618)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Updated Dependencies * @vapor-ui/icons\@1.2.1 ## 1.3.0 ### Avatar * fix double rendering `FallbackPrimitive` ([#556](https://github.com/goorm-dev/vapor-ui/pull/556)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * deprecate `imageElement`/`fallbackElement` props ([#556](https://github.com/goorm-dev/vapor-ui/pull/556)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Spinner * add new `Spinner` component ([#567](https://github.com/goorm-dev/vapor-ui/pull/567)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Segmented Control * add new `SegmentedControl` component ([#569](https://github.com/goorm-dev/vapor-ui/pull/569)) - Thanks [@noahchoii](https://github.com/noahchoii)! ## 1.2.1 ### Menu * correct `gap` scale of list components ([#553](https://github.com/goorm-dev/vapor-ui/pull/553)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Select * correct `gap` scale of list components ([#553](https://github.com/goorm-dev/vapor-ui/pull/553)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### MultiSelect * correct `gap` scale of list components ([#553](https://github.com/goorm-dev/vapor-ui/pull/553)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Updated Dependencies * @vapor-ui/icons\@1.2.0 ## 1.2.0 ### All * add `forwardRef` to `Portal` elements ([#499](https://github.com/goorm-dev/vapor-ui/pull/499)) - Thanks [@noahchoii](https://github.com/noahchoii)! * support for functional className and style prop across all components ([#517](https://github.com/goorm-dev/vapor-ui/pull/517)) - Thanks [@noahchoii](https://github.com/noahchoii)! * implemente interaction layer corners using `box-shadow` and add animations to `Checkbox`, \`Radio ([#515](https://github.com/goorm-dev/vapor-ui/pull/515)) - Thanks [@noahchoii](https://github.com/noahchoii)! * adjust dark `background.hint.100` to improve surface hierarchy on overlay backgrounds ([#518](https://github.com/goorm-dev/vapor-ui/pull/518)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * remove css all property ([#493](https://github.com/goorm-dev/vapor-ui/pull/493)) - Thanks [@noahchoii](https://github.com/noahchoii)! * remove duplication from deprecated sprinkles ([#494](https://github.com/goorm-dev/vapor-ui/pull/494)) - Thanks [@noahchoii](https://github.com/noahchoii)! * split sprinkles className and hash with `-` ([#495](https://github.com/goorm-dev/vapor-ui/pull/495)) - Thanks [@noahchoii](https://github.com/noahchoii)! * bump @base-ui/react v1.2.0 ([#497](https://github.com/goorm-dev/vapor-ui/pull/497)) - Thanks [@noahchoii](https://github.com/noahchoii)! * bump @base-ui/react version v1.3.0 ([#519](https://github.com/goorm-dev/vapor-ui/pull/519)) - Thanks [@vapor-ui](https://github.com/vapor-ui)! ### Button * add `@base-ui/react` headless to the `Button` component ([#501](https://github.com/goorm-dev/vapor-ui/pull/501)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Checkbox * fix: improve checkbox border styles and interaction overlay sizing ([#354](https://github.com/goorm-dev/vapor-ui/pull/354)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Select * set the width and height of the `Select.TriggerIcon`'s SVG to 100%. ([#504](https://github.com/goorm-dev/vapor-ui/pull/504)) - Thanks [@noahchoii](https://github.com/noahchoii)! * deprecate `Select.PlaceholderPrimitive` component. Use `data-placeholder` for custom styling. ([#500](https://github.com/goorm-dev/vapor-ui/pull/500)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Switch * composite missing `className` prop ([#498](https://github.com/goorm-dev/vapor-ui/pull/498)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Toast * respect the user's reduced motion preference in toast animations ([#525](https://github.com/goorm-dev/vapor-ui/pull/525)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Etc. * add `:active` pseudo-selector to utility CSS properties ([#535](https://github.com/goorm-dev/vapor-ui/pull/535)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Updated Dependencies * @vapor-ui/icons\@1.1.0 ## 1.1.0 ### General changes * expand utility props and scoping it `$css` ([#476](https://github.com/goorm-dev/vapor-ui/pull/476)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Etc. * Change `useMutationObserver` hook to use only ref ([#332](https://github.com/goorm-dev/vapor-ui/pull/332)) - Thanks [@SimYunSup](https://github.com/SimYunSup)! ### Skeleton * Add new `Skeleton` component ([#481](https://github.com/goorm-dev/vapor-ui/pull/481)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Updated Dependencies * @vapor-ui/icons\@1.0.1 ## 1.0.0 ### Checkbox / Switch / Radio * **Breaking Change**: Root element changed from `HTMLButtonElement` to `HTMLSpanElement` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Dialog * fix(dialog): correct ReactElement type parameters in DialogPopup props ([#438](https://github.com/goorm-dev/vapor-ui/pull/438)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! Fixed incorrect type parameters for `portalElement` and `overlayElement` in `DialogPopup.Props` from `typeof Component` to `Component.Props`. ### Field * **Breaking Change**: `validationMode` default changed from `onBlur` to `onSubmit` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * **New Feature**: `Field.Item`: New component added for improved accessibility when using Checkbox, Radio, Switch with Field ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### FloatingBar * feat(FloatingBar): export `EventDetails` type ([#437](https://github.com/goorm-dev/vapor-ui/pull/437)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! Export `ChangeEventDetails` type from `FloatingBarRoot` namespace for docs-extractor compatibility. ### Form * **Breaking Change**: `onClearErrors` prop removed (now auto-handled internally) ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Menu * **Breaking Change**: `openOnHover`, `delay`, `closeDelay` props moved from `Menu.Root` to `Menu.Trigger` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### NavigationMenu * **Breaking Change**: `Link`: `selected` prop renamed to `current` (for Breadcrumb API consistency) ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * **Breaking Change**: `data-selected` attribute changed to `data-active` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Popover * **Breaking Change**: `openOnHover`, `delay`, `closeDelay` props moved from `Popover.Root` to `Popover.Trigger` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Radio Card * removed the size prop from the RadioCard component and simplified its styling by removing typography mixins ([#442](https://github.com/goorm-dev/vapor-ui/pull/442)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Tabs * fix(tabs): correct indicator position when list has padding ([#434](https://github.com/goorm-dev/vapor-ui/pull/434)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! Fix indicator positioning issue when Tabs.List has padding-inline (horizontal) or padding-block (vertical). The indicator now correctly positions itself by explicitly setting `left: 0` (horizontal) or `top: 0` (vertical), ensuring it uses only the CSS variables for positioning regardless of padding. * **Breaking Change**: `Tabs.Root`: `loop` prop renamed to `loopFocus` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * **Breaking Change**: `activateOnFocus` default changed from `true` to `false` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * **Breaking Change**: `data-selected` attribute changed to `data-active` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Tooltip * **Breaking Change**: `Tooltip.Root`: `hoverable` prop renamed to `disableHoverablePopup` (logic inverted) ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * **Breaking Change**: `delay`, `closeDelay` props moved from `Tooltip.Root` to `Tooltip.Trigger` ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Etc. * Migrate to Base UI v1.1.0 ([#453](https://github.com/goorm-dev/vapor-ui/pull/453)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * Updated internal utilities to use official @base-ui/utils package (v0.2.4) ([#443](https://github.com/goorm-dev/vapor-ui/pull/443)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * fix: prevent passing props to Fragment in `createRender` ([#403](https://github.com/goorm-dev/vapor-ui/pull/403)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! Fixed React warning `Invalid prop 'ref' supplied to 'React.Fragment'` by wrapping Fragment returns in a render callback to avoid `cloneElement` props merging. ### Updated Dependencies * @vapor-ui/icons\@1.0.0 ## 1.0.0-beta.12 ### Button * Update secondary button fill variant text color to use foreground.secondary\[200] for improved contrast ([#427](https://github.com/goorm-dev/vapor-ui/pull/427)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Dialog * adjust to max-width in dialog ([#394](https://github.com/goorm-dev/vapor-ui/pull/394)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Field * feat(field): add typography and foreground props to Field.Label ([#399](https://github.com/goorm-dev/vapor-ui/pull/399)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Floatingbar * add new `FloatingBar` component ([#359](https://github.com/goorm-dev/vapor-ui/pull/359)) - Thanks [@noahchoii](https://github.com/noahchoii)! * clone elements & enhance customizability ([#359](https://github.com/goorm-dev/vapor-ui/pull/359)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Tabs * Refactor Tabs component structure for better customization ([#429](https://github.com/goorm-dev/vapor-ui/pull/429)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * Changed `Tabs.Trigger` to `Tabs.Button` for clearer semantics * Extracted `Tabs.ListPrimitive` and `Tabs.IndicatorPrimitive` for enhanced customization * Added fill and line variant support with updated styles * Updated type definitions and utility props for better developer experience ### Updated Dependencies * @vapor-ui/icons\@1.0.0-beta.7 ## 1.0.0-beta.11 ### Text Input * Correct background-color of TextInput component ([#387](https://github.com/goorm-dev/vapor-ui/pull/387)) - Thanks [@agetbase](https://github.com/agetbase)! ### Etc. * clone elements & enhance customizability ([#359](https://github.com/goorm-dev/vapor-ui/pull/359)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Updated Dependencies * @vapor-ui/hooks\@1.0.0-beta.6 * @vapor-ui/icons\@1.0.0-beta.6 ## 1.0.0-beta.10 ### Toast * avoid overflowing when toast width is wider than view port width ([#390](https://github.com/goorm-dev/vapor-ui/pull/390)) - Thanks [@noahchoii](https://github.com/noahchoii)! ## 1.0.0-beta.9 ### Toast * remove toastManager ([#383](https://github.com/goorm-dev/vapor-ui/pull/383)) - Thanks [@noahchoii](https://github.com/noahchoii)! ## 1.0.0-beta.8 ### Toast * add new `Toast` component ([#376](https://github.com/goorm-dev/vapor-ui/pull/376)) - Thanks [@noahchoii](https://github.com/noahchoii)! ## 1.0.0-beta.7 ### Menu * Updated Menu.Item paddingRight from 6px to 12px to match Figma design specification ([#325](https://github.com/goorm-dev/vapor-ui/pull/325)) - Thanks [@agetbase](https://github.com/agetbase)! * Correct MenuPositionerPrimitive sideOffset from 8px to 4px to match Figma spec ([#342](https://github.com/goorm-dev/vapor-ui/pull/342)) - Thanks [@agetbase](https://github.com/agetbase)! ### Pagination * add new `Pagination` component ([#329](https://github.com/goorm-dev/vapor-ui/pull/329)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Table * add new `Table` component ([#294](https://github.com/goorm-dev/vapor-ui/pull/294)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Etc. * synchronized color tokens with figma ([#340](https://github.com/goorm-dev/vapor-ui/pull/340)) - Thanks [@noahchoii](https://github.com/noahchoii)! * **BREAKING CHANGE**: Remove `stretch` prop from Button, IconButton, and NavigationMenu components ([#368](https://github.com/goorm-dev/vapor-ui/pull/368)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! The `stretch` prop has been removed to align with Figma's component variant system. In Figma, width control is handled via "Fill Container" (Auto Layout), not as a component variant. **Migration Guide:** Replace `stretch` prop with Tailwind's `w-full` utility class: ```tsx // Before ... // After ... ``` **Why this change:** * Maintains Figma-React design system parity (SSOT principle) * Follows "React Props = Figma Variants" architectural principle * Aligns with Vapor UI's 4-layer component architecture (Container, Interaction, Contents, Slot) * Layout concerns should be handled by parent containers, not component props ## 1.0.0-beta.6 It contains the same code as the previous version. Please refer to that version. ## 1.0.0-beta.5 ### Button * update horizontal padding for small size (`050 (4px)` -> `100 (8px)`) ([#323](https://github.com/goorm-dev/vapor-ui/pull/323)) - Thanks [@agetbase](https://github.com/agetbase)! ### Checkbox * fix checkbox borderRadius sync error ([#267](https://github.com/goorm-dev/vapor-ui/pull/267)) - Thanks [@SimYunSup](https://github.com/SimYunSup)! ### Field * add default layout styles to field.label ([#289](https://github.com/goorm-dev/vapor-ui/pull/289)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Form * add new `Form` component ([#256](https://github.com/goorm-dev/vapor-ui/pull/256)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Icon Button * Fixed a CSS dependency order issue where `IconButton` styles loaded before `Button` styles, causing incorrect style inheritance. ### Radio * adjust indicator size to account for border ([#291](https://github.com/goorm-dev/vapor-ui/pull/291)) - Thanks [@SimYunSup](https://github.com/SimYunSup)! ### Radio Card * add new component `RadioCard` ([#284](https://github.com/goorm-dev/vapor-ui/pull/284)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Radio Group * synchronize the aria-labelledby with the recieved id prop ([#327](https://github.com/goorm-dev/vapor-ui/pull/327)) - Thanks [@noahchoii](https://github.com/noahchoii)! * replace layout styles into layout component like VStack, HStack ([#288](https://github.com/goorm-dev/vapor-ui/pull/288)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Text Input * add component layer ([#253](https://github.com/goorm-dev/vapor-ui/pull/253)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Theme * add ThemeScope component and migrate to data-attribute based theming ([#278](https://github.com/goorm-dev/vapor-ui/pull/278)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Theme Provider * remove ThemeScript and simplify ThemeProvider ([#240](https://github.com/goorm-dev/vapor-ui/pull/240)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Etc. * enabled CSS tree shaking ([#298](https://github.com/goorm-dev/vapor-ui/pull/298)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * Component CSS is now automatically imported by each component file. * add white foreground variant to foreground recipe ([#305](https://github.com/goorm-dev/vapor-ui/pull/305)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * export component with namespace ([#276](https://github.com/goorm-dev/vapor-ui/pull/276)) - Thanks [@noahchoii](https://github.com/noahchoii)! * migrate to base-ui beta v4 ([#292](https://github.com/goorm-dev/vapor-ui/pull/292)) - Thanks [@noahchoii](https://github.com/noahchoii)! * change components interface ([#360](https://github.com/goorm-dev/vapor-ui/pull/360)) - Thanks [@noahchoii](https://github.com/noahchoii)! * missing component exports in entry file ([#248](https://github.com/goorm-dev/vapor-ui/pull/248)) - Thanks [@noahchoii](https://github.com/noahchoii)! * add uilitiy css props ([#326](https://github.com/goorm-dev/vapor-ui/pull/326)) - Thanks [@noahchoii](https://github.com/noahchoii)! * rename `CombinedContent` to `Content` ([#247](https://github.com/goorm-dev/vapor-ui/pull/247)) - Thanks [@noahchoii](https://github.com/noahchoii)! * unify cascade layers under `vapor` namespace ([#334](https://github.com/goorm-dev/vapor-ui/pull/334)) - Thanks [@noahchoii](https://github.com/noahchoii)! * standardize state attributes for form components ([#282](https://github.com/goorm-dev/vapor-ui/pull/282)) - Thanks [@noahchoii](https://github.com/noahchoii)! * feat: rename color tokens ([#261](https://github.com/goorm-dev/vapor-ui/pull/261)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * prevent loading font while building CSS ([#265](https://github.com/goorm-dev/vapor-ui/pull/265)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * correct background color of interaction layer in dark mode ([#335](https://github.com/goorm-dev/vapor-ui/pull/335)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Updated Dependencies * @vapor-ui/icons\@1.0.0-beta.5 ## 0.6.0 ### Callout * add flex layout for icons and text alignment ([#181](https://github.com/goorm-dev/vapor-ui/pull/181)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Collapsible * add new `Collapsible` component ([#197](https://github.com/goorm-dev/vapor-ui/pull/197)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Field * add new `Field` components ([#224](https://github.com/goorm-dev/vapor-ui/pull/224)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Input Group * add new `InputGroup` component ([#230](https://github.com/goorm-dev/vapor-ui/pull/230)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Multi Select * add new `MultiSelect` component ([#225](https://github.com/goorm-dev/vapor-ui/pull/225)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Navigation Menu * Migrate `Nav` to `NavigationMenu` ([#211](https://github.com/goorm-dev/vapor-ui/pull/211)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Popover * add new `Popover` component ([#156](https://github.com/goorm-dev/vapor-ui/pull/156)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Select * add new `Select` component ([#222](https://github.com/goorm-dev/vapor-ui/pull/222)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Sheet * add new `Sheet` component ([#187](https://github.com/goorm-dev/vapor-ui/pull/187)) - Thanks [@noahchoii](https://github.com/noahchoii)! * edit spacing style implementation ([#238](https://github.com/goorm-dev/vapor-ui/pull/238)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Tabs * add new `Tabs` component ([#157](https://github.com/goorm-dev/vapor-ui/pull/157)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Textarea * Add new `Textarea` component ([#209](https://github.com/goorm-dev/vapor-ui/pull/209)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Tooltip * eidt tooltip offset ([#212](https://github.com/goorm-dev/vapor-ui/pull/212)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Etc. * change the overlay component interface ([#195](https://github.com/goorm-dev/vapor-ui/pull/195)) - Thanks [@noahchoii](https://github.com/noahchoii)! * remove `Label` sub-component from all form elements ([#204](https://github.com/goorm-dev/vapor-ui/pull/204)) - Thanks [@noahchoii](https://github.com/noahchoii)! * migrate to `Base UI` ([#186](https://github.com/goorm-dev/vapor-ui/pull/186)) - Thanks [@noahchoii](https://github.com/noahchoii)! * support readonly props in all of form elements ([#208](https://github.com/goorm-dev/vapor-ui/pull/208)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! * fix svg rendering issue on safari ([#237](https://github.com/goorm-dev/vapor-ui/pull/237)) - Thanks [@noahchoii](https://github.com/noahchoii)! * remove active style when provided readonly ([#246](https://github.com/goorm-dev/vapor-ui/pull/246)) - Thanks [@noahchoii](https://github.com/noahchoii)! * ensure focus styles take precedence over hover styles ([#200](https://github.com/goorm-dev/vapor-ui/pull/200)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Updated Dependencies * @vapor-ui/icons\@0.4.0 ## 0.5.0 ### Avatar * align CSS variable with build identifiers config ([#176](https://github.com/goorm-dev/vapor-ui/pull/176)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Breadcrumb * add new `Breadcrumb` component ([#151](https://github.com/goorm-dev/vapor-ui/pull/151)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Button * add `no-wrap` CSS properties ([#114](https://github.com/goorm-dev/vapor-ui/pull/114)) - Thanks [@jun094](https://github.com/jun094)! ### Menu * add new `Menu` component ([#147](https://github.com/goorm-dev/vapor-ui/pull/147)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Radio Group * add background-color(white) to RadioGroup Indicator ([#146](https://github.com/goorm-dev/vapor-ui/pull/146)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Tooltip * add new `Tooltip` component ([#150](https://github.com/goorm-dev/vapor-ui/pull/150)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Etc. * enhance vanillaExtractPlugin identifiers ([#161](https://github.com/goorm-dev/vapor-ui/pull/161)) - Thanks [@noahchoii](https://github.com/noahchoii)! * remove hover state when used touchscreen ([#158](https://github.com/goorm-dev/vapor-ui/pull/158)) - Thanks [@noahchoii](https://github.com/noahchoii)! * add `VComponentProps` ([#168](https://github.com/goorm-dev/vapor-ui/pull/168)) - Thanks [@noahchoii](https://github.com/noahchoii)! * add `box-shadow` tokens ([#143](https://github.com/goorm-dev/vapor-ui/pull/143)) - Thanks [@noahchoii](https://github.com/noahchoii)! * enhance vanillaExtractPlugin identifiers for better debugging ([#149](https://github.com/goorm-dev/vapor-ui/pull/149)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Updated Dependencies * @vapor-ui/icons\@1.0.0 ## 0.4.0 ### Badge * align text to center ([#137](https://github.com/goorm-dev/vapor-ui/pull/137)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Radio Group * remove incorrectly injected props ([#125](https://github.com/goorm-dev/vapor-ui/pull/125)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Etc. * change CSS layer names to `theme`, `reset`, `components`, and `utilities` ([#138](https://github.com/goorm-dev/vapor-ui/pull/138)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * add Tailwind CSS v4 preset ([#98](https://github.com/goorm-dev/vapor-ui/pull/98)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * improve DX by overhauling CSS bundling strategy ([#121](https://github.com/goorm-dev/vapor-ui/pull/121)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * add foreground mixin to style entry point ([#142](https://github.com/goorm-dev/vapor-ui/pull/142)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Updated Dependencies * @vapor-ui/icons\@0.2.0 ## 0.3.1 ### Theme Provider * add `primaryColor` props for user custom ([#87](https://github.com/goorm-dev/vapor-ui/pull/87)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ## 0.3.0 ### Etc. * remove sprinkles on each components ([#88](https://github.com/goorm-dev/vapor-ui/pull/88)) - Thanks [@noahchoii](https://github.com/noahchoii)! * correct CSS layer priority ([#94](https://github.com/goorm-dev/vapor-ui/pull/94)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ## 0.2.1 ### Theme Provider * support RSC ([#82](https://github.com/goorm-dev/vapor-ui/pull/82)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ## 0.2.0 ### Callout * add new `Callout` component ([#67](https://github.com/goorm-dev/vapor-ui/pull/67)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Checkbox * add new `Checkbox` Component ([#58](https://github.com/goorm-dev/vapor-ui/pull/58)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Dialog * edit dialog animation style ([#72](https://github.com/goorm-dev/vapor-ui/pull/72)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Radio Group * add new `RadioGroup` component ([#76](https://github.com/goorm-dev/vapor-ui/pull/76)) - Thanks [@noahchoii](https://github.com/noahchoii)! ### Switch * add new `Switch` component - Thanks [@noahchoii](https://github.com/noahchoii)! ### Etc. * remove `@vapor-ui/icons` for resolving storybook build error ([#57](https://github.com/goorm-dev/vapor-ui/pull/57)) - Thanks [@noahchoii](https://github.com/noahchoii)! * prevent code splitting while tsup build ([#81](https://github.com/goorm-dev/vapor-ui/pull/81)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * resolve circular dependency in vanilla-extract ([#73](https://github.com/goorm-dev/vapor-ui/pull/73)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * optimize build system for component bundling ([#73](https://github.com/goorm-dev/vapor-ui/pull/73)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ## 0.1.0 ### Etc. * create package ([#48](https://github.com/goorm-dev/vapor-ui/pull/48)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! # Css Generator URL: /docs/releases/css-generator Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/releases/css-generator.md @vapor-ui/css-generator 패키지의 릴리즈 노트입니다. # @vapor-ui/css-generator ## 1.0.0-beta.8 ### Tokens * **BREAKING CHANGE**: rename `color-background-canvas` token to `color-canvas` ([#378](https://github.com/goorm-dev/vapor-ui/pull/378)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! The canvas background token has been renamed for better semantic clarity and consistency: * Token name: `color-background-canvas` → `color-canvas` * CSS variable: `--vapor-color-background-canvas` → `--vapor-color-canvas` **Migration required:** * Update all references from `color-background-canvas` to `color-canvas` * Replace CSS variables from `--vapor-color-background-canvas` to `--vapor-color-canvas` ### Updated Dependencies * @vapor-ui/color-generator\@1.0.0-beta.8 ## 1.0.0-beta.7 ### Updated Dependencies * @vapor-ui/color-generator\@1.0.0-beta.7 ## 1.0.0-beta.6 ### Etc. * feat: update color generator & color palette ([#337](https://github.com/goorm-dev/vapor-ui/pull/337)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Updated Dependencies * @vapor-ui/color-generator\@1.0.0-beta.6 ## 1.0.0-beta.5 ### Theme * feat(theme): Add ThemeScope component and migrate to data-attribute based theming ([#278](https://github.com/goorm-dev/vapor-ui/pull/278)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Etc. * feat: create @vapor-ui/color-generator & @vapor-ui/css-generator ([#234](https://github.com/goorm-dev/vapor-ui/pull/234)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! * feat: update color tokens ([#261](https://github.com/goorm-dev/vapor-ui/pull/261)) - Thanks [@ZeroChoi2781](https://github.com/ZeroChoi2781)! ### Updated Dependencies * @vapor-ui/color-generator\@1.0.0 # ESLint URL: /docs/releases/eslint-plugin-vapor Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/releases/eslint-plugin-vapor.md eslint-plugin-vapor 패키지의 릴리즈 노트입니다. # eslint-plugin-vapor ## 1.1.1 ### Typography * fix the code font family name to `"Fira Code"` and apply it to the `code1` / `code2` typography styles ([#748](https://github.com/goorm-dev/vapor-ui/pull/748)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ## 1.1.0 ### Rules * add new rules related with usage of design-tokens ([#626](https://github.com/goorm-dev/vapor-ui/pull/626)) - Thanks [@noahchoii](https://github.com/noahchoii)! ## 1.0.0 ### Eslint Plugin Vapor * create new `eslint-plugin-vapor` for accessibilities ([#457](https://github.com/goorm-dev/vapor-ui/pull/457)) - Thanks [@noahchoii](https://github.com/noahchoii)! # Icons URL: /docs/releases/icons Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/releases/icons.md @vapor-ui/icons 패키지의 릴리즈 노트입니다. # @vapor-ui/icons ## 1.3.1 ### Icons * regenerate icon components with the SVGR + svgo pipeline ([#722](https://github.com/goorm-dev/vapor-ui/pull/722)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Etc. * Update icons from Figma ([#706](https://github.com/goorm-dev/vapor-ui/pull/706)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **Updated Basic Icons:** `TriangleOutlineIcon` **Removed:** * Basic Icons: `ProgrammingIcon`, `ProgrammingOutlineIcon` * Update icons from Figma ([#739](https://github.com/goorm-dev/vapor-ui/pull/739)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **Updated Basic Icons:** `FolderNewOutlineIcon` **Updated Symbol Icons:** `InstagramIcon`, `InstagramColorIcon` ## 1.3.0 ### Icons * Add new icons from Figma ([#673](https://github.com/goorm-dev/vapor-ui/pull/673)) - Thanks [@noahchoii](https://github.com/noahchoii)! **New Basic Icons:** `IdIcon`, `DevicesIcon` ## 1.2.1 ### Etc. * Update icons from Figma ([#608](https://github.com/goorm-dev/vapor-ui/pull/608)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **Updated Basic Icons:** `CopyOutlineIcon` ## 1.2.0 ### Etc. * Add new icons from Figma ([#554](https://github.com/goorm-dev/vapor-ui/pull/554)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **New Basic Icons:** `LicenseIcon`, `RewardedAdsIcon` ## 1.1.0 ### Etc. * Add new icons from Figma ([#539](https://github.com/goorm-dev/vapor-ui/pull/539)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **New Basic Icons:** `TriangleOutlineIcon` ## 1.0.1 ### Etc. * Check the center alignment of the IntelliSenseEventIcon ([#480](https://github.com/goorm-dev/vapor-ui/pull/480)) - Thanks [@noahchoii](https://github.com/noahchoii)! **Updated Symbol Icons:** `IntelliSenseEventIcon`, `IntelliSenseEventOutlineIcon` ## 1.0.0 ### Etc. * Sync icons from Figma and remove deleted HeadingOutlineIcon ([#430](https://github.com/goorm-dev/vapor-ui/pull/430)) - Thanks [@github-actions](https://github.com/apps/github-actions)! * Update icons from Figma ([#449](https://github.com/goorm-dev/vapor-ui/pull/449)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **Updated Symbol Icons:** `VscodeColorIcon` **New Symbol Icons:** `SouthKoreaColorIcon`, and 195 other country icons ## 1.0.0-beta.7 ### Icon Base * remove iconType ([#231](https://github.com/goorm-dev/vapor-ui/pull/231)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Etc. * Update icons from Figma ([#406](https://github.com/goorm-dev/vapor-ui/pull/406)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **Updated Basic Icons:** `Heading2OutlineIcon`, `StrikeOutlineIcon`, `ChecklistOutlineIcon`, `Heading3OutlineIcon`, `Heading4OutlineIcon`, `Heading1OutlineIcon` ## 1.0.0-beta.6 ### Etc. * clone elements & enhance customizability ([#359](https://github.com/goorm-dev/vapor-ui/pull/359)) - Thanks [@noahchoii](https://github.com/noahchoii)! * Add new icons from Figma ([#396](https://github.com/goorm-dev/vapor-ui/pull/396)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **New:** `ChecklistOutlineIcon`, `StrikeOutlineIcon`, `Heading3OutlineIcon`, `Heading2OutlineIcon`, `Heading1OutlineIcon`, `Heading4OutlineIcon` ## 1.0.0-beta.5 ### Etc. * Add new icons from Figma ([#264](https://github.com/goorm-dev/vapor-ui/pull/264)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **New:** `DocktoBottomIcon`, `SideNavIcon`, `SideNavOutlineIcon`, `DocktoBottomOutlineIcon` **Updated:** * Basic Icons: `PanelOpenIcon`, `PanelOpenOutlineIcon` * Update icons from Figma ([#285](https://github.com/goorm-dev/vapor-ui/pull/285)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **Updated:** `TreeCollapseIcon` ## 0.4.0 ### Icon Base * adjust prop precedence for dimensions(width, height, size) ([#182](https://github.com/goorm-dev/vapor-ui/pull/182)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! ### Etc. * Add new icons from Figma ([#207](https://github.com/goorm-dev/vapor-ui/pull/207)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **New:** `MediumIcon` **Updated:** * Symbol Icons: `FirefoxColorIcon` * update icons from Figma ([#217](https://github.com/goorm-dev/vapor-ui/pull/217)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **Updated:** `TerminalWindowOutlineIcon` ## 0.3.0 ### Etc. * add new icons from Figma ([#179](https://github.com/goorm-dev/vapor-ui/pull/179)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **New:** `LinearScaleOutlineIcon` **Updated:** * Basic Icons: `PlayIcon`, `ReplaceIcon`, `ClassIcon`, `ArrowUpOutlineIcon`, `ArrowDownOutlineIcon`, `TerminalOutlineIcon`, `ViewShrinkOutlineIcon`, `FolderSearchIcon`, `StarOutlineIcon`, `PriceOutlineIcon`, `HistoryOutlineIcon`, `CardsOutlineIcon`, `ZoomOutOutlineIcon`, `IntelliSensePropertyOutlineIcon`, `CorrectOutlineIcon`, `ChevronDoubleRightOutlineIcon`, `AutoCodeOutlineIcon`, `ChapterOutlineIcon` * Symbol Icons: `RstudioColorIcon` * add new icons from Figma ([#198](https://github.com/goorm-dev/vapor-ui/pull/198)) - Thanks [@github-actions](https://github.com/apps/github-actions)! **New:** `SidenavIcon` ## 0.2.0 ### Etc. * add new icons and update existing icon components ([#119](https://github.com/goorm-dev/vapor-ui/pull/119)) - Thanks [@MaxLee-dev](https://github.com/MaxLee-dev)! **New Icons Added** * `AlignJustifyOutlineIcon`, `CopyAsMarkdownOutlineIcon`, `IndentDecreaseOutlineIcon`, `SlotIcon`, `TextScanOutlineIcon` **Updated** * Updated approximately 190 existing icons with refined SVG paths and improved rendering * Minor coordinate adjustments for better visual consistency * Enhanced clipPath definitions where needed ## 0.1.0 ### Minor Changes * 68b001c: create avatar , badge , box , button , card , dialog , flex , grid , h-stack , icon-button, nav , text-input , text , theme-provider , v-stack # Composition URL: /docs/getting-started/composition Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/getting-started/(handbook)/composition.mdx 기본 props로 해결되지 않을 때, Vapor UI 컴포넌트의 구조를 직접 제어하는 방법을 설명합니다. 기본 props로 해결되지 않을 때 두 가지 방법으로 커스터마이징할 수 있습니다. Primitive는 Vapor UI 컴포넌트의 내부 구조를 이루는 최소 단위 컴포넌트입니다. * **Primitive가 없는 컴포넌트** (`Button`, `Badge`, `TextInput` 등): `render` prop으로 커스터마이징합니다. * **Primitive가 있는 컴포넌트** (`Dialog`, `Sheet`, `Tabs` 등): Primitive를 직접 조합해 내부 구조를 제어합니다. 컴포넌트에 Primitive가 있는지 확인하려면 각 컴포넌트 문서의 Props Table에서 `XxxPrimitive` 항목을 찾으세요. ## render prop으로 렌더링 제어하기 `render` prop은 두 가지 형태로 사용할 수 있습니다. **ReactElement 형태** — HTML 태그나 외부 컴포넌트로 교체할 때 사용합니다. ```tsx import { Button, Card, Dialog } from '@vapor-ui/core'; import Link from 'next/link'; // div → article로 교체 } /> // Next.js Link로 교체 ``` **함수 형태** — 컴포넌트의 내부 state에 따라 렌더링 내용을 동적으로 바꿀 때 사용합니다. 함수는 `(props, state)` 두 인자를 받습니다. ```tsx import { Switch } from '@vapor-ui/core'; import { DarkIcon, LightIcon } from '@vapor-ui/icons'; export default function Example() { return ( ( {state.checked ? : } )} /> ); } ``` ## Primitive 직접 조합하기 Primitive를 직접 조합하면 Portal 위치, Overlay 렌더링 순서 등 레이어 구조 전체를 제어할 수 있습니다. ```tsx import { Button, Dialog } from '@vapor-ui/core'; export default function Example() { return ( 열기 제목 내용 닫기} /> ); } ``` # Styling URL: /docs/getting-started/styling Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/getting-started/(handbook)/styling.mdx Vapor UI 컴포넌트를 스타일링하고 커스터마이징하는 방법을 설명합니다. Vapor UI는 단순한 스타일 오버라이드부터 컴포넌트 구조 변경까지 단계별 커스터마이징을 지원합니다. ## 1. 기본 스타일링 (className, style) 가장 익숙한 방식인 `className`과 `style`을 사용합니다. 빠른 스타일 수정이 필요하거나 기존 CSS 체계를 유지해야 할 때 적합합니다. ### className 외부 CSS 파일이나 CSS 모듈의 클래스를 적용합니다. ```tsx import { Button } from '@vapor-ui/core'; export default function Example() { return ; } ``` ### style 인라인 스타일을 통해 동적인 스타일을 직접 주입합니다. ```tsx import { Button } from '@vapor-ui/core'; export default function Example() { return ( ); } ``` ## 2. `$css` 속성 Vapor UI가 권장하는 기본 방식입니다. 별도의 CSS 파일 없이 컴포넌트에서 직접 스타일을 제어할 수 있습니다. ### 기본 CSS 속성 수정 CSS 속성을 객체 형태로 전달하여 스타일을 수정합니다. ```tsx import { Button } from '@vapor-ui/core'; export default function Example() { return ( ); } ``` ### 토큰 기반 스타일링 디자인 토큰을 사용해 일관된 스타일을 유지하세요. 타입 지원을 통해 오타를 방지할 수 있습니다. ```tsx import { Button } from '@vapor-ui/core'; export default function Example() { return ( ); } ``` ### 반응형 및 가상 선택자 반응형 조건(breakpoints)과 가상 선택자(`_hover` 등)를 `$css` 안에서 한 번에 정의할 수 있습니다. ```tsx import { Button } from '@vapor-ui/core'; export default function Example() { return ( ); } ``` ## 3. 상태 기반 스타일링 컴포넌트의 상태(checked, invalid 등)에 따라 스타일을 유연하게 변경할 수 있습니다. ### 함수형 className, style `className`과 `style`에 함수를 전달하여 현재 상태에 맞는 스타일을 동적으로 반환합니다. ```tsx import { Checkbox } from '@vapor-ui/core'; export default function Example() { return ( (state.checked ? 'checkbox-checked' : 'checkbox-unchecked')} style={(state) => ({ backgroundColor: state.invalid ? 'color-mix(in srgb, red 12%, transparent)' : undefined, })} /> ); } ``` ### Data Attributes 컴포넌트 상태는 `data-*` 속성으로 노출됩니다. 상태별 스타일 로직을 CSS 파일로 분리할 때 유용합니다. ```css /* 데이터 속성을 활용한 스타일 정의 */ .checkbox[data-checked] { background-color: var(--vapor-color-background-primary-200); } .checkbox[data-invalid] { border-color: var(--vapor-color-border-danger); } ``` ### 함수형 render `render` prop을 사용하면 렌더링되는 엘리먼트 자체와 클래스 구성을 직접 제어할 수 있습니다. ```tsx import { NavigationMenu } from '@vapor-ui/core'; export default function Example() { return ( ( )} /> ); } ``` # Tailwind CSS v4 URL: /docs/getting-started/tailwindcss-v4 Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/getting-started/(handbook)/tailwindcss-v4.mdx Vapor UI와 함께 Tailwind CSS v4를 사용하세요. 이 문서에서는 Vapor UI와 Tailwind CSS v4를 함께 설정하는 방법을 설명합니다. 설정을 완료하면 Vapor UI 컴포넌트와 Tailwind 유틸리티 클래스를 함께 사용할 수 있습니다. ## 설정 메인 CSS 파일(예: `global.css`)에 아래 코드를 추가합니다. ```css /* global.css */ /* 1. 스타일 우선순위 정의 */ @layer tw-theme, vapor, tw-utilities; @import '@vapor-ui/core/tailwind.css'; /* 2. Tailwind CSS 연결 */ @import 'tailwindcss/theme.css' layer(tw-theme); @import 'tailwindcss/utilities.css' layer(tw-utilities); ``` 설정이 완료되면 Vapor UI 컴포넌트와 Tailwind 유틸리티를 함께 사용할 수 있습니다. ## Vapor 유틸리티 클래스 `v-` 접두사가 붙은 Vapor 전용 유틸리티 클래스를 사용할 수 있습니다. ### 디자인 토큰 클래스 Vapor의 색상, 간격, 둥근 모서리를 Tailwind 문법으로 사용합니다. `v-` 접두사를 추가하여 Vapor 디자인 토큰을 적용합니다. * **색상**: `bg-v-blue-500`, `text-v-red-300`, `border-v-gray-900` * **간격**: `p-v-100`, `m-v-200`, `gap-v-400`, `w-v-400` * **둥근 모서리**: `rounded-v-200`, `rounded-t-v-400` * **폰트 굵기**: `font-v-400`, `font-v-700` Tailwind의 모든 [유틸리티 클래스](https://tailwindcss.com/docs/theme#theme-variable-namespaces)와 조합할 수 있습니다. ### 시맨틱 유틸리티 클래스 의미 기반 색상 클래스를 제공합니다. Primary, Success, Warning 등의 역할에 맞는 색상을 적용합니다. * **배경색**: `bg-v-primary`, `bg-v-secondary`, `bg-v-success`, `bg-v-warning`, `bg-v-danger` * **텍스트색**: `text-v-primary`, `text-v-success`, `text-v-warning`, `text-v-danger`, `text-v-accent` * **테두리색**: `border-v-primary`, `border-v-success`, `border-v-warning`, `border-v-danger` ## 스타일 우선순위 CSS `@layer` 규칙으로 스타일 우선순위 계층을 정의합니다. 1. Vapor 컴포넌트 기본 스타일 2. Vapor 유틸리티 클래스 3. Tailwind 유틸리티 (가장 높은 우선순위) Tailwind 유틸리티가 가장 높은 우선순위를 가지므로 `className="bg-blue-500"`와 같은 클래스로 Vapor 컴포넌트를 커스터마이징할 수 있습니다. ## CSS Reset 설정 Vapor UI는 필요한 스타일 초기화를 포함합니다. Tailwind의 `preflight.css`는 사용하지 않는 것을 권장합니다. `preflight.css`가 필요한 경우 레이어 순서를 다음과 같이 조정합니다. ```css /* preflight를 사용해야 하는 경우 */ @layer tw-theme, vapor.theme, tw-base, vapor.reset, vapor.components, vapor.utilities, tw-utilities; @import '@vapor-ui/core/tailwind.css'; @import 'tailwindcss/theme.css' layer(tw-theme); @import 'tailwindcss/preflight.css' layer(tw-base); @import 'tailwindcss/utilities.css' layer(tw-utilities); ``` > 이 설정은 스타일 충돌 가능성이 있으므로 필요한 경우에만 사용합니다. # Theming URL: /docs/getting-started/theming Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/getting-started/(handbook)/theming.mdx Vapor UI의 테마 시스템에 대해 설명합니다. # Design Tokens URL: /docs/getting-started/tokens Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/getting-started/(handbook)/tokens.mdx Vapor UI의 디자인 토큰에 대해 설명합니다. # Design Principles URL: /docs/getting-started/principles Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/getting-started/(overview)/principles.mdx Vapor UI의 컴포넌트 아키텍처와 개발 철학을 이끄는 핵심 디자인 원칙 이 문서에서는 Vapor UI의 설계 철학과 6가지 핵심 원칙을 설명합니다. 이 원칙들을 이해하면 컴포넌트를 더 효과적으로 활용할 수 있습니다. ## 1. Preset 기반의 컴파운드 패턴 Vapor UI는 합성 컴포넌트 패턴을 채택하여 편의성과 유연성을 함께 제공합니다. 빠른 구현이 필요할 때는 Preset 컴포넌트를, 세밀한 제어가 필요할 때는 Primitive 컴포넌트를 사용합니다. ```tsx // Preset 패턴 (빠르고 간편) Trigger Contents // Primitive 패턴 (완전한 제어) Trigger Contents ``` 이 접근법의 장점은 다음과 같습니다. * **빠른 시작**: Preset 컴포넌트로 즉시 구현할 수 있습니다. * **세밀한 제어**: Primitive 컴포넌트로 커스텀 동작을 구현할 수 있습니다. * **혼합 사용**: 같은 애플리케이션에서 두 패턴을 함께 사용할 수 있습니다. ## 2. 접근성 Vapor UI는 [Base UI](https://base-ui.com/react/overview/quick-start)를 기반으로 [WCAG 2.2](https://www.w3.org/TR/WCAG22/) AA를 준수합니다. [키보드 네비게이션](https://www.w3.org/TR/WCAG22/#keyboard-accessible)과 [포커스 표시](https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance)를 기본으로 지원합니다. ### 접근성 기능 * **Base UI 통합**: ARIA 속성, 키보드 내비게이션, 스크린 리더를 자동으로 지원합니다. * **색상 대비 준수**: 자체 개발한 Color Generator가 WCAG AA/AAA 대비 비율을 보장합니다. * **수학적 디자인 토큰**: 일관된 시각적 위계를 위해 수학적 비율로 생성된 토큰을 사용합니다. ```tsx // 적절한 ARIA 속성과 키보드 처리가 자동으로 포함됨 설정 열기 {/* 포커스 관리와 ESC 키 처리가 내장됨 */} ``` ### Color Generator 시스템 Color Generator는 지각적 색상 모델을 사용하여 접근성을 충족하는 색상 팔레트를 생성합니다. ```tsx // 색상이 자동으로 대비 요구사항을 충족함 Primary Success Warning ``` ## 3. 일관된 네이밍 규칙 모든 컴포넌트는 일관된 네이밍 규칙을 따릅니다. 이 규칙을 통해 컴포넌트 사용법을 예측할 수 있습니다. * **독립 컴포넌트**: 단일 이름을 사용합니다. * **합성 컴포넌트**: Dot Notation 표기법을 사용합니다. ```tsx // 단일 컴포넌트 상태 // 합성 컴포넌트 프로젝트 상태 현재 개발 진행상황 섹션 1 섹션 2 섹션 3 ``` ## 4. 예측 가능한 속성 명명 컴포넌트 속성은 시각적 옵션과 논리적 상태를 기반으로 체계적인 규칙을 따릅니다. ### 시각적 옵션 ```tsx // 크기 변형은 일관된 스케일을 따름 ); } ``` ```css .input-label { color: var(--vapor-color-foreground-normal-100, #525463); font-size: var(--vapor-typography-fontSize-050, 0.75rem); font-weight: var(--vapor-typography-fontWeight-500); line-height: var(--vapor-typography-lineHeight-050, 1.125rem); /* 150% */ letter-spacing: var(--vapor-typography-letterSpacing-000, 0); } .checkbox-label { color: var(--vapor-color-foreground-normal-100, #2b2d36); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } .helper-text { color: var(--vapor-color-foreground-hint, #6c6e7e); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } ``` ### Type: SignUp ```tsx import './signup-form.css'; import { useState } from 'react'; import { Box, Button, Checkbox, Field, Form, HStack, IconButton, Select, Text, TextInput, VStack, } from '@vapor-ui/core'; import { ChevronRightOutlineIcon } from '@vapor-ui/icons'; const jobs = [ { label: '개발자', value: 'developer' }, { label: '디자이너', value: 'designer' }, { label: '프로덕트 매니저', value: 'product-manager' }, { label: '기타', value: 'etc' }, ]; export default function SignupForm() { const [passwordCheck, setPasswordCheck] = useState(''); // const passwordCheck = useRef(''); return ( event.preventDefault()} />} $css={{ gap: '$250', width: '100%', padding: '$300', borderRadius: '$300', border: '1px solid var(--vapor-color-border-normal)', }} > } className="input-label" $css={{ flexDirection: 'column' }} > 이메일 이메일을 입력해주세요. 유효한 이메일 형식이 아닙니다. } className="input-label" $css={{ flexDirection: 'column' }} > 비밀번호 setPasswordCheck(value)} required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).{8,16}" /> 8~16자, 대소문자 영문, 숫자, 특수문자 포함 비밀번호를 입력해주세요. 유효한 비밀번호 형식이 아닙니다. } className="input-label" $css={{ flexDirection: 'column' }} > 비밀번호 확인 8~16자, 대소문자 영문, 특수문자 포함 비밀번호를 입력해주세요. 비밀번호를 다시 확인해주세요. } className="input-label" $css={{ flexDirection: 'column' }} > 이름 이름을 입력해주세요. } className="input-label" $css={{ flexDirection: 'column' }} > 직업 {jobs.map((job) => ( {job.label} ))} } className="checkbox-label" $css={{ alignItems: 'center' }} > 필수 약관에 모두 동의 } className="checkbox-label" $css={{ alignItems: 'center' }} > 이용 약관 동의 } className="checkbox-label" $css={{ alignItems: 'center' }} > 개인 정보 수집 이용 동의 이미 계정이 있으세요? ); } ``` ```css .input-label { color: var(--vapor-color-foreground-normal-100, #525463); font-size: var(--vapor-typography-fontSize-050, 0.75rem); font-weight: var(--vapor-typography-fontWeight-500); line-height: var(--vapor-typography-lineHeight-050, 1.125rem); /* 150% */ letter-spacing: var(--vapor-typography-letterSpacing-000, 0); } .checkbox-label { color: var(--vapor-color-foreground-normal-100, #2b2d36); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } .helper-text { color: var(--vapor-color-foreground-hint, #6c6e7e); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } ``` ### Type: Authentication ```tsx import { Children, cloneElement, isValidElement, useState } from 'react'; import './authentication-form.css'; import { Button, Field, Form, Select, Text, TextInput, VStack } from '@vapor-ui/core'; const codes = { '+82': '🇰🇷 +82', '+1': '🇺🇸 +1', '+34': '🇪🇸 +34', '+33': '🇫🇷 +33', '+39': '🇮🇹 +39', '+44': '🇬🇧 +44', '+81': '🇯🇵 +81', '+86': '🇨🇳 +86', '+7': '🇷🇺 +7', }; export default function AuthenticationForm() { const [phoneNumber, setPhoneNumber] = useState(''); const handleChange = (e: React.ChangeEvent) => { setPhoneNumber(e.target.value); }; const regex = /^[0-9\s-()]{6,20}$/; return ( e.preventDefault()} />} $css={{ gap: '$400', width: '100%', padding: '$300', borderRadius: '$300', border: '1px solid var(--vapor-color-border-normal)', }} > 핸드폰 번호 {Object.entries(codes).map(([value, label]) => ( {label} ))} 핸드폰 번호를 입력해주세요. 올바른 핸드폰 번호를 입력해주세요. 인증번호 인증번호를 입력해주세요. ); } interface GroupProps { attached?: boolean; children?: React.ReactNode; } const Group = ({ attached = false, children: childrenProp }: GroupProps) => { const children = Children.map(childrenProp, (child, index) => { if (!isValidElement(child)) return; const childProps = child.props as { style?: React.CSSProperties }; return cloneElement(child as React.ReactElement<{ style?: React.CSSProperties }>, { style: { '--group-index': index, ...childProps.style } as React.CSSProperties, ...(index === 0 ? { 'data-first-item': '' } : {}), ...(index === Children.count(childrenProp) - 1 ? { 'data-last-item': '' } : {}), }); }); return (
{children}
); }; ``` ```css .input-label { color: var(--vapor-color-foreground-normal-100, #525463); font-size: var(--vapor-typography-fontSize-050, 0.75rem); font-weight: var(--vapor-typography-fontWeight-500); line-height: var(--vapor-typography-lineHeight-050, 1.125rem); /* 150% */ letter-spacing: var(--vapor-typography-letterSpacing-000, 0); } .group { display: flex; align-items: center; gap: 0; &.attached { & > [data-first-item] { border-right: none; border-top-right-radius: 0; border-bottom-right-radius: 0; } & > [data-last-item] { border: 1px solid var(--vapor-color-border-normal, #d1d2d8); border-top-left-radius: 0; border-bottom-left-radius: 0; } & > *:not([data-first-item]):not([data-last-item]) { border: 1px solid var(--vapor-color-border-normal, #d1d2d8); border-right: none; border-radius: 0; } } } ```
### Type: Research ```tsx import './research-form.css'; import { Button, Checkbox, Field, Form, HStack, MultiSelect, Radio, RadioGroup, Select, Switch, Text, TextInput, VStack, } from '@vapor-ui/core'; const jobs = [ { label: '프론트엔드 개발자', value: 'frontend-engineer' }, { label: '백엔드 개발자', value: 'backend-engineer' }, { label: '풀스택 개발자', value: 'fullstack-engineer' }, { label: '모바일 앱 개발자', value: 'app-engineer' }, { label: 'DevOps/클라우드 엔지니어', value: 'devops-engineer' }, ]; const stacks = [ { label: 'HTML/CSS', value: 'html-css' }, { label: 'JavaScript', value: 'javascript' }, { label: 'React', value: 'react' }, { label: 'Vue.js', value: 'vue' }, { label: 'Next.js', value: 'nextjs' }, ]; export default function ResearchForm() { return ( event.preventDefault()} />} $css={{ gap: '$500', padding: '$300', borderRadius: '$300', width: '100%', border: '1px solid var(--vapor-color-border-normal)', }} > 기본 정보를 입력해주세요. 이름 이름을 입력해주세요. 직업 {jobs.map((job) => ( {job.label} ))} 스택 {stacks.map((stack) => ( {stack.label} ))} 만족도를 선택해주세요. 매우 만족 보통 불만족 좋았던 강의는 무엇인가요? 중복 선택 가능 멘토님 강연 능력 주제(협업 및 커뮤니케이션 스킬) 전반적인 강의 내용 세미나 자료 기타 개인 정보 수신 동의 } > 서비스 메일 수신 동의 } > 이벤트성 광고 수신 동의 ); } ``` ```css .input-label { color: var(--vapor-color-foreground-normal-100, #525463); font-size: var(--vapor-typography-fontSize-050, 0.75rem); font-weight: var(--vapor-typography-fontWeight-500); line-height: var(--vapor-typography-lineHeight-050, 1.125rem); /* 150% */ letter-spacing: var(--vapor-typography-letterSpacing-000, 0); } .checkbox-label { color: var(--vapor-color-foreground-normal-100, #2b2d36); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } .radio-label { color: var(--vapor-color-foreground-normal-100, #2b2d36); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } ``` ### Type: Filter ```tsx import './filter-form.css'; import type { FormEvent } from 'react'; import { useCallback, useRef, useState } from 'react'; import { Box, Button, Checkbox, Collapsible, Field, Form, HStack, Radio, RadioGroup, Text, VStack, } from '@vapor-ui/core'; import { ChevronDownOutlineIcon, RefreshOutlineIcon } from '@vapor-ui/icons'; // 초기값 정의 type FormData = typeof FORM_SCHEME; const FORM_SCHEME = { view: 'recent', sort: { feedback: false, buttons: false, 'data-display': false, overlay: false, inputs: false, navigation: false, utils: false, }, packs: { 'goorm-dev/vapor-core': false, 'goorm-dev/vapor-component': false, 'vapor-ui/core': false, }, status: { active: false, inactive: false, draft: false }, tag: { ui: false, 'open-source': false, performance: false }, }; export default function FilterForm() { const formRef = useRef(null); const [formData, setFormData] = useState({ view: FORM_SCHEME.view, sort: { ...FORM_SCHEME.sort }, packs: { ...FORM_SCHEME.packs }, status: { ...FORM_SCHEME.status }, tag: { ...FORM_SCHEME.tag }, }); const getFieldValues = useCallback( (fieldName: T): FormData[T] => formData[fieldName], [formData], ); const updateFormData = useCallback( (fieldName: keyof FormData, key: string, checked: boolean) => { setFormData((prev) => { const field = prev[fieldName]; if (typeof field !== 'object') return prev; return { ...prev, [fieldName]: { ...field, [key]: checked } }; }); }, [], ); // 라디오 버튼 변경 핸들러 const handleRadioChange = useCallback((fieldName: keyof FormData, value: string) => { setFormData((prev) => ({ ...prev, [fieldName]: value })); }, []); // 체크박스 변경 핸들러 const handleCheckboxChange = useCallback( (fieldName: keyof FormData, key: string) => (checked: boolean) => { updateFormData(fieldName, key, checked); }, [updateFormData], ); const selectedSortCount = Object.values(getFieldValues('sort')).filter(Boolean).length; const handleReset = (event: FormEvent) => { event.preventDefault(); setFormData({ view: FORM_SCHEME.view, sort: { ...FORM_SCHEME.sort }, packs: { ...FORM_SCHEME.packs }, status: { ...FORM_SCHEME.status }, tag: { ...FORM_SCHEME.tag }, }); }; return ( }> Filter } $css={{ border: 'none', marginBlock: '$150', height: '1px', width: '100%', backgroundColor: '$basic-gray-300', }} /> View }> handleRadioChange('view', value as string) } > Recent Most Popular Sort {selectedSortCount} }> Feedback Buttons Data Display Overlay Inputs Navigation Utils Package }> goorm-dev/vapor-core goorm-dev/vapor-component vapor-ui/core Status }> Active Inactive Draft Tag }> UI Open Source Performance ); } ``` ```css .checkbox-label { color: var(--vapor-color-foreground-normal-100, #2b2d36); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } .radio-label { color: var(--vapor-color-foreground-normal-100, #2b2d36); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } .collapsible-trigger { width: 100%; display: flex; align-items: center; justify-content: space-between; transition: transform 150ms ease; } .trigger-icon { transition: transform 150ms ease; &:where([data-open] &) { transform: rotate(180deg); } &:where([data-closed] &) { transform: rotate(0); } } ``` ### Type: BottomSheetFilter ```tsx import './sheet-form.css'; import type { FormEvent } from 'react'; import { useCallback, useState } from 'react'; import { Button, Checkbox, Field, Form, Sheet, Tabs, VStack } from '@vapor-ui/core'; import { RefreshOutlineIcon } from '@vapor-ui/icons'; type FormData = typeof FORM_SCHEME; const FORM_SCHEME = { sort: { feedback: false, buttons: true, 'data-display': false, overlay: false, inputs: true, navigation: false, utils: false, }, packs: { 'goorm-dev/vapor-core': true, 'goorm-dev/vapor-component': false, 'vapor-ui/core': false, }, status: { active: true, inactive: false, draft: false, }, tag: { ui: true, 'open-source': false, performance: false, }, }; export default function SheetForm() { const [formData, setFormData] = useState(() => { return { sort: { ...FORM_SCHEME.sort }, packs: { ...FORM_SCHEME.packs }, status: { ...FORM_SCHEME.status }, tag: { ...FORM_SCHEME.tag }, }; }); const getFieldValues = useCallback( (fieldName: T): FormData[T] => formData[fieldName], [formData], ); const updateFormData = useCallback( (fieldName: keyof FormData, key: string, checked: boolean) => { setFormData((prev) => { const field = prev[fieldName]; if (typeof field !== 'object') return prev; return { ...prev, [fieldName]: { ...field, [key]: checked } }; }); }, [], ); const handleCheckboxChange = useCallback( (fieldName: keyof FormData, key: string) => (checked: boolean) => { updateFormData(fieldName, key, checked); }, [updateFormData], ); const handleReset = useCallback((event: FormEvent) => { event.preventDefault(); setFormData({ sort: { ...FORM_SCHEME.sort }, packs: { ...FORM_SCHEME.packs }, status: { ...FORM_SCHEME.status }, tag: { ...FORM_SCHEME.tag }, }); }, []); return ( } $css={{ gap: '$250', width: '100%', padding: '$300', borderRadius: '$300', border: '1px solid #eee', }} > }>Open Filter Filter Sort Package Status Tag {/* Sort */} Feedback Buttons Data Display Overlay Inputs Navigation Utils {/* Package */} goorm-dev/vapor-core goorm-dev/vapor-component vapor-ui/core {/* Status */} Active Inactive Draft {/* Tag */} UI Open Source Performance }> Apply ); } ``` ```css .checkbox-label { color: var(--vapor-color-foreground-normal-100, #2b2d36); font-size: var(--vapor-typography-fontSize-075, 0.875rem); font-weight: var(--vapor-typography-fontWeight-400); line-height: var(--vapor-typography-lineHeight-075, 1.375rem); /* 157.143% */ letter-spacing: var(--vapor-typography-letterSpacing-100, -0.00625rem); } .popup { border-top-left-radius: var(--vapor-size-borderRadius-300); border-top-right-radius: var(--vapor-size-borderRadius-300); } .tabs { height: 100%; } .tabs-list { padding-inline: 0; } .tabs-panel { padding-block: var(--vapor-size-space-200); } .header { padding: var(--vapor-size-space-250) var(--vapor-size-space-200) 0; } .body { padding-inline: var(--vapor-size-space-200); } .footer { gap: var(--vapor-size-space-100); padding-top: var(--vapor-size-space-100); } .refresh-button { flex-shrink: 0; } .apply-button { flex-shrink: 0; flex-grow: 1; } ``` # Navbar URL: /docs/components/patterns/nav-bar Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/patterns/nav-bar/index.mdx 사용자의 액션에 대한 피드백 혹은 서비스에 대한 메시지를 제공할 때 사용할 수 있습니다. 상황에 따라 컬러와 좌측 아이콘, 닫기 버튼을 적절히 사용합니다. ### Left Aligned Navbar ```tsx import './block.css'; import type { ComponentProps } from 'react'; import { Avatar, Collapsible, HStack, IconButton, NavigationMenu, Sheet } from '@vapor-ui/core'; import { BellOnIcon, ChevronDownOutlineIcon, CloseOutlineIcon, MenuOutlineIcon, } from '@vapor-ui/icons'; export default function Block1() { return ( Features Pricing Templates }> } > } > } > } > Features Container SBOM Pricing Templates ); } const LogoSvg = (props: ComponentProps<'svg'>) => { return ( ); }; ``` ```css .navbar-desktop { display: inherit; @media (max-width: 767px) { display: none; } } .navbar-mobile { display: none; @media (max-width: 767px) { display: inherit; } } .logo { flex-shrink: 0; } .vertical-navigation-menu { width: 100%; } .collapsible-trigger { width: 100%; justify-content: space-between; } .link-item { justify-content: flex-start; } .nested-link-item { justify-content: flex-start; padding-left: var(--vapor-size-space-250); } ``` ### Center Aligned Navbar ```tsx import './block.css'; import type { ComponentProps } from 'react'; import { Avatar, Collapsible, HStack, IconButton, NavigationMenu, Sheet } from '@vapor-ui/core'; import { BellOnIcon, ChevronDownOutlineIcon, CloseOutlineIcon, MenuOutlineIcon, } from '@vapor-ui/icons'; export default function Block2() { return ( Features Pricing Templates }> } > } > } > } > Features Container SBOM Pricing Templates ); } const LogoSvg = (props: ComponentProps<'svg'>) => { return ( ); }; ``` ```css .navbar-desktop { display: inherit; @media (max-width: 767px) { display: none; } } .navbar-mobile { display: none; @media (max-width: 767px) { display: inherit; } } .logo { flex-shrink: 0; } .vertical-navigation-menu { width: 100%; } .collapsible-trigger { width: 100%; justify-content: space-between; } .link-item { justify-content: flex-start; } .nested-link-item { justify-content: flex-start; padding-left: var(--vapor-size-space-250); } ``` ### Right Aligned Navbar ```tsx import './block.css'; import type { ComponentProps } from 'react'; import { Avatar, Collapsible, HStack, IconButton, NavigationMenu, Sheet } from '@vapor-ui/core'; import { BellOnIcon, ChevronDownOutlineIcon, CloseOutlineIcon, MenuOutlineIcon, } from '@vapor-ui/icons'; export default function Block3() { return ( Features Pricing Templates }> } > } > } > } > Features Container SBOM Pricing Templates ); } const LogoSvg = (props: ComponentProps<'svg'>) => { return ( ); }; ``` ```css .navbar-desktop { display: inherit; @media (max-width: 767px) { display: none; } } .navbar-mobile { display: none; @media (max-width: 767px) { display: inherit; } } .logo { flex-shrink: 0; } .vertical-navigation-menu { width: 100%; } .collapsible-trigger { width: 100%; justify-content: space-between; } .link-item { justify-content: flex-start; } .nested-link-item { justify-content: flex-start; padding-left: var(--vapor-size-space-250); } ``` ### Navbar with Login Button ```tsx import './block.css'; import type { ComponentProps } from 'react'; import { Button, Collapsible, HStack, IconButton, NavigationMenu, Sheet } from '@vapor-ui/core'; import { ChevronDownOutlineIcon, CloseOutlineIcon, MenuOutlineIcon } from '@vapor-ui/icons'; export default function Block4() { return ( Features Pricing Templates } > } > } > Features Container SBOM Pricing Templates ); } const LogoSvg = (props: ComponentProps<'svg'>) => { return ( ); }; ``` ```css .navbar-desktop { display: inherit; @media (max-width: 767px) { display: none; } } .navbar-mobile { display: none; @media (max-width: 767px) { display: inherit; } } .logo { flex-shrink: 0; } .vertical-navigation-menu { width: 100%; } .collapsible-trigger { width: 100%; justify-content: space-between; } .link-item { justify-content: flex-start; } .nested-link-item { justify-content: flex-start; padding-left: var(--vapor-size-space-250); } ``` ### Logo Centered Navbar ```tsx import './logo.css'; import type { ComponentProps } from 'react'; import { Button, HStack } from '@vapor-ui/core'; export default function Block5() { return ( ); } const LogoSvg = (props: ComponentProps<'svg'>) => { return ( ); }; ``` ```css .logo { flex-shrink: 0; } ``` ### Page Navigation Navbar ```tsx import './logo.css'; import type { ComponentProps } from 'react'; import { HStack, IconButton } from '@vapor-ui/core'; import { BackPageOutlineIcon, ForwardPageOutlineIcon } from '@vapor-ui/icons'; export default function Block6() { return ( ); } const LogoSvg = (props: ComponentProps<'svg'>) => { return ( ); }; ``` ```css .logo { flex-shrink: 0; } ``` # Table URL: /docs/components/patterns/table Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/patterns/table/index.mdx 데이터의 구조화된 표현을 제공하는 데 사용됩니다. 이 문서는 대량의 데이터를 다루는 Data Table의 구현 예시를 안내합니다. Data Table은 데이터를 효율적으로 시각화하고 관리하는 강력한 도구이지만, 내부적으로 복잡한 상태 관리와 로직을 필요로 합니다. 이러한 기능을 컴포넌트 내부에 강결합하면 유지보수가 어렵고 확장성이 떨어지는 문제가 발생할 수 있습니다. 이에 따라 Vapor UI의 Table 컴포넌트는 순수한 뷰(View) 역할에 집중하여 기본적인 구조와 스타일을 제공합니다. 이 문서에서는 `@tanstack/react-table`과 같은 Headless UI 라이브러리를 활용하여 다양한 기능을 유연하게 구현하는 방법을 예시로 제공합니다. ### Basic ```tsx import { Badge, Table } from '@vapor-ui/core'; const datas = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; export default function Basic() { return ( Name Status Role Last Active {datas.map((data, index) => ( {data.name} {data.status.toUpperCase()} {data.role} {data['last-active']} ))} ); } ``` ### Checkbox ```tsx import { useMemo, useState } from 'react'; import { type ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { Badge, Card, Checkbox, Table } from '@vapor-ui/core'; export default function Basic() { const [rowSelection, setRowSelection] = useState({}); const columns = useMemo[]>( () => [ { id: 'select', header: ({ table }) => ( table.toggleAllRowsSelected(value)} $css={{ justifySelf: 'center' }} /> ), cell: ({ row }) => ( row.toggleSelected(value)} $css={{ justifySelf: 'center' }} /> ), }, { header: 'Name', accessorKey: 'name', }, { header: 'Status', accessorKey: 'status', cell: ({ getValue }) => { const status = getValue(); return ( {status.toUpperCase()} ); }, }, { header: 'Role', accessorKey: 'role', }, { header: 'Last Active', accessorKey: 'last-active', }, ], [], ); const table = useReactTable({ data: datas, columns, state: { rowSelection }, enableRowSelection: true, onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), }); return ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => { return ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ); })} ); })} ); } type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; ``` ### Ordering ```tsx import { useMemo, useState } from 'react'; import { type ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { Badge, Box, Card, Table } from '@vapor-ui/core'; export default function Ordering() { const [rowSelection, setRowSelection] = useState({}); const columns = useMemo[]>( () => [ { id: 'select', header: () => ID, cell: ({ row }) => {row.index + 1}, }, { header: 'Name', accessorKey: 'name', }, { header: 'Status', accessorKey: 'status', cell: ({ getValue }) => { const status = getValue(); return ( {status.toUpperCase()} ); }, }, { header: 'Role', accessorKey: 'role', }, { header: 'Last Active', accessorKey: 'last-active', }, ], [], ); const table = useReactTable({ data: datas, columns, state: { rowSelection }, enableRowSelection: true, onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), }); return ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} ); })} ); } type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; ``` ### Sticky ```tsx import type { CSSProperties } from 'react'; import { useMemo, useState } from 'react'; import type { Column, Table as TanstackTable } from '@tanstack/react-table'; import { type ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { Badge, Box, Card, Table } from '@vapor-ui/core'; export default function Basic() { const [rowSelection, setRowSelection] = useState({}); const columns = useMemo[]>( () => [ { header: () => ID, accessorKey: 'id', cell: ({ row }) => {row.index + 1}, }, { header: 'Name', accessorKey: 'name', cell: ({ row }) => {row.getValue('name')}, }, { header: 'Status', accessorKey: 'status', cell: ({ row }) => { const status = row.getValue('status'); return ( {status.toUpperCase()} ); }, }, { header: 'Role', accessorKey: 'role', }, { header: 'Last Active', accessorKey: 'last-active', }, ], [], ); const table = useReactTable({ data: datas, columns, state: { rowSelection, columnPinning: { left: ['id', 'name'] } }, enableRowSelection: true, onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), }); return ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( columnSizingHandler(thElem, table, header.column) } $css={{ backgroundColor: '$basic-gray-050' }} style={{ ...getCommonPinningStyles(header.column) }} > {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} ); })} ); } type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const getCommonPinningStyles = (column: Column): CSSProperties => { const isPinned = column.getIsPinned(); const lastPinnedColumn = isPinned === 'left' && column.getIsLastColumn('left'); return { boxShadow: lastPinnedColumn ? '-3px 0 0 0 rgba(0, 0, 0, 0.06) inset' : undefined, left: isPinned === 'left' ? `${column.getStart('left')}px` : undefined, position: isPinned ? 'sticky' : 'unset', zIndex: isPinned ? 1 : undefined, }; }; const activeness: Record = { active: 'success', inactive: 'hint', }; const columnSizingHandler = ( thElem: HTMLTableCellElement | null, table: TanstackTable, column: Column, ) => { if (!thElem) return; if (table.getState().columnSizing[column.id] !== undefined) return; if (table.getState().columnSizing[column.id] === thElem.getBoundingClientRect().width) return; table.setColumnSizing((prevSizes) => ({ ...prevSizes, [column.id]: thElem.getBoundingClientRect().width, })); }; ``` ### Collapsed ```tsx import type { CSSProperties } from 'react'; import { useMemo, useState } from 'react'; import type { Column, ColumnDef, OnChangeFn, RowData, TableFeature, Table as TanstackTable, Updater, } from '@tanstack/react-table'; import { flexRender, getCoreRowModel, makeStateUpdater, useReactTable, } from '@tanstack/react-table'; import { Badge, Box, Card, HStack, IconButton, Table } from '@vapor-ui/core'; import { ChevronDoubleLeftOutlineIcon, ChevronDoubleRightOutlineIcon } from '@vapor-ui/icons'; // asdf export default function Collapsed() { const columns = useMemo[]>( () => [ { header: () => ID, accessorKey: 'id', cell: ({ row }) => {row.index + 1}, }, { header: ({ column }) => { const isCollapsed = column.getIsCollapsed(); const IconElement = isCollapsed ? ChevronDoubleRightOutlineIcon : ChevronDoubleLeftOutlineIcon; return ( {isCollapsed ? '' : 'Name'} column.toggleCollapsed()} color="secondary" > ); }, accessorKey: 'name', cell: ({ row, column }) => { const isCollapsed = column.getIsCollapsed(); return ( {row.getValue('name')} ); }, }, { header: 'Status', accessorKey: 'status', cell: ({ row }) => { const status = row.getValue('status'); return ( {status.toUpperCase()} ); }, }, { header: () => Role, accessorKey: 'role', }, { header: () => Last Active, accessorKey: 'last-active', }, ], [], ); const [columnCollapsed, setColumnCollapsed] = useState(['name']); // 초기에 접힐 컬럼들 const table = useReactTable({ _features: [ColumnCollapsedFeature], data: datas, columns, state: { columnPinning: { left: ['id', 'name'] }, columnCollapsed, }, enableRowSelection: true, getCoreRowModel: getCoreRowModel(), onColumnCollapsedChange: setColumnCollapsed, }); return ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( columnSizingHandler(thElem, table, header.column) } $css={{ backgroundColor: '$basic-gray-050' }} style={{ ...getCommonPinningStyles(header.column) }} > {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} ); })} ); } /* -----------------------------------------------------------------------------------------------*/ type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const getCommonPinningStyles = (column: Column): CSSProperties => { const isPinned = column.getIsPinned(); const lastPinnedColumn = isPinned === 'left' && column.getIsLastColumn('left'); return { boxShadow: lastPinnedColumn ? '-3px 0 0 0 rgba(0, 0, 0, 0.06) inset' : undefined, left: isPinned === 'left' ? `${column.getStart('left')}px` : undefined, position: isPinned ? 'sticky' : 'unset', zIndex: isPinned ? 1 : undefined, }; }; const activeness: Record = { active: 'success', inactive: 'hint', }; const columnSizingHandler = ( thElem: HTMLTableCellElement | null, table: TanstackTable, column: Column, ) => { if (!thElem) return; const currentSize = table.getState().columnSizing[column.id]; const elementWidth = thElem.getBoundingClientRect().width; if (currentSize === elementWidth) return; table.setColumnSizing((prevSizes) => ({ ...prevSizes, [column.id]: elementWidth, })); }; /* -----------------------------------------------------------------------------------------------*/ export type ColumnCollapsedState = string[]; export interface ColumnCollapsedTableState { columnCollapsed: ColumnCollapsedState; } export interface ColumnCollapsedOptions { enableColumnCollapsed?: boolean; onColumnCollapsedChange?: OnChangeFn; } export interface ColumnCollapsedColumnInstance { getIsCollapsed: () => boolean; toggleCollapsed: () => void; } /* eslint-disable @typescript-eslint/no-unused-vars */ declare module '@tanstack/react-table' { interface TableState extends ColumnCollapsedTableState {} interface TableOptionsResolved extends ColumnCollapsedOptions {} interface Column< TData extends RowData, TValue = unknown, > extends ColumnCollapsedColumnInstance {} } /* eslint-enable @typescript-eslint/no-unused-vars */ export const ColumnCollapsedFeature: TableFeature = { getInitialState: (state): ColumnCollapsedTableState => { return { columnCollapsed: [], ...state, }; }, getDefaultOptions: ( table: TanstackTable, ): ColumnCollapsedOptions => { return { enableColumnCollapsed: true, onColumnCollapsedChange: makeStateUpdater('columnCollapsed', table), }; }, createColumn: ( column: Column, table: TanstackTable, ): void => { column.getIsCollapsed = () => { return table.getState().columnCollapsed?.includes(column.id) ?? false; }; column.toggleCollapsed = () => { const currentState = column.getIsCollapsed(); const updater: Updater = (old) => { if (currentState) return old.filter((id) => id !== column.id); return [...old, column.id]; }; table.options.onColumnCollapsedChange?.(updater); }; }, }; ``` ### Sort ```tsx import { useMemo, useState } from 'react'; import type { SortingState } from '@tanstack/react-table'; import { type ColumnDef, flexRender, getCoreRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table'; import { Badge, Box, Card, HStack, IconButton, Table } from '@vapor-ui/core'; import { ControlCommonIcon } from '@vapor-ui/icons'; export default function Sort() { const columns = useMemo[]>( () => [ { id: 'index', header: 'ID', accessorFn: (_, index) => index + 1, cell: ({ getValue }) => ( {String(getValue() ?? '.')} ), }, { header: 'Name', accessorKey: 'name', cell: (info) => info.getValue(), }, { accessorKey: 'status', cell: ({ getValue }) => { const status = getValue(); return ( {status.toUpperCase()} ); }, }, { accessorKey: 'role', cell: (info) => info.getValue(), }, { accessorKey: 'last-active', cell: (info) => info.getValue(), sortingFn: 'datetime', }, ], [], ); const [sorting, setSorting] = useState([]); const table = useReactTable({ data: datas, columns, state: { sorting }, enableRowSelection: true, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), onSortingChange: setSorting, }); return ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => { return ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ); })} ); })} ); } type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; ``` ### Scroll ```tsx import { useMemo, useState } from 'react'; import { type ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { Badge, Box, Card, Table } from '@vapor-ui/core'; export default function Scroll() { const [rowSelection, setRowSelection] = useState({}); const columns = useMemo[]>( () => [ { accessorKey: 'id', header: () => ID, cell: ({ row }) => {row.index + 1}, }, { header: 'Name', accessorKey: 'name', cell: ({ row }) => {row.getValue('name')}, }, { header: 'Status', accessorKey: 'status', cell: ({ row }) => { const status = row.getValue('status'); return ( {status.toUpperCase()} ); }, }, { header: () => 'Role', accessorKey: 'role', }, { header: () => 'Last Active', accessorKey: 'last-active', }, ], [], ); const table = useReactTable({ data: datas, columns, state: { rowSelection, columnPinning: { left: ['id', 'name'] } }, enableRowSelection: true, onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), }); return ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} ); })} ); } type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; ``` ### Filter ```tsx import { useMemo, useState } from 'react'; import type { ColumnFiltersState, Row } from '@tanstack/react-table'; import { type ColumnDef, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, useReactTable, } from '@tanstack/react-table'; import { Badge, Box, Button, Card, HStack, MultiSelect, Select, Table, Text, TextInput, } from '@vapor-ui/core'; import { PlusOutlineIcon, SearchOutlineIcon } from '@vapor-ui/icons'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const customFilterFn = (row: Row, columnId: string, filterValue: any) => { if (!filterValue || filterValue.length === 0) return true; const cellValue = row.getValue(columnId) as string; return filterValue.includes(cellValue); }; export default function Scroll() { const columns = useMemo[]>( () => [ { header: () => ID, accessorKey: 'id', size: 0, // prevent cumulative layout shift cell: ({ row }) => {row.index + 1}, }, { header: 'Name', accessorKey: 'name', size: 0, // prevent cumulative layout shift cell: ({ row }) =>
{row.getValue('name')}
, }, { header: 'Status', accessorKey: 'status', cell: ({ row }) => { const status = row.getValue('status'); return ( {status.toUpperCase()} ); }, filterFn: customFilterFn, }, { header: 'Role', accessorKey: 'role', filterFn: customFilterFn, }, { header: 'Last Active', accessorKey: 'last-active', }, ], [], ); const [columnFilters, setColumnFilters] = useState([]); const table = useReactTable({ data: datas, columns, state: { columnFilters }, enableRowSelection: true, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), onColumnFiltersChange: setColumnFilters, }); return ( 출석부 table.getColumn('name')?.setFilterValue(value) } /> { table.getColumn('status')?.setFilterValue(value); }} content={ <> Active Inactive } /> table.getColumn('role')?.setFilterValue(value) } content={ <> Designer Developer } /> col.getIsVisible()) .map((col) => col.id)} content={table .getAllColumns() .filter((column) => column.getCanHide()) .map((column) => ( column.toggleVisibility()} > {column.id} ))} /> {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.length ? ( table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} ); }) ) : ( 검색 결과가 없습니다. )} table.setPageSize(Number(value))} > {(value) => `${value}개씩 보기`} {[5, 10, 20, 30, 40, 50].map((pageSize) => ( {pageSize} ))} ); } type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; /* -----------------------------------------------------------------------------------------------*/ interface FilterSelectProps extends React.ComponentProps { triggerLabel: string; content: React.ReactNode; } const FilterSelect = ({ content, triggerLabel, ...props }: FilterSelectProps) => { return ( } style={{ width: 'unset' }} > {triggerLabel} {content} ); }; ```
### Pagination ```tsx import { useMemo, useState } from 'react'; import type { ColumnFiltersState, Row } from '@tanstack/react-table'; import { type ColumnDef, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, useReactTable, } from '@tanstack/react-table'; import { Badge, Box, Button, Card, HStack, MultiSelect, Pagination, Select, Table, Text, TextInput, } from '@vapor-ui/core'; import { PlusOutlineIcon, SearchOutlineIcon } from '@vapor-ui/icons'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const customFilterFn = (row: Row, columnId: string, filterValue: any) => { if (!filterValue || filterValue.length === 0) return true; const cellValue = row.getValue(columnId) as string; return filterValue.includes(cellValue); }; export default function WithPagination() { const columns = useMemo[]>( () => [ { header: () => ID, accessorKey: 'id', size: 0, // prevent cumulative layout shift cell: ({ row }) => {row.index + 1}, }, { header: 'Name', accessorKey: 'name', size: 0, // prevent cumulative layout shift cell: ({ row }) =>
{row.getValue('name')}
, }, { header: 'Status', accessorKey: 'status', cell: ({ row }) => { const status = row.getValue('status'); return ( {status.toUpperCase()} ); }, filterFn: customFilterFn, }, { header: 'Role', accessorKey: 'role', filterFn: customFilterFn, }, { header: 'Last Active', accessorKey: 'last-active', }, ], [], ); const [columnFilters, setColumnFilters] = useState([]); const table = useReactTable({ data: datas, columns, state: { columnFilters }, enableRowSelection: true, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), onColumnFiltersChange: setColumnFilters, }); return ( 출석부 table.getColumn('name')?.setFilterValue(value) } /> { table.getColumn('status')?.setFilterValue(value); }} content={ <> Active Inactive } /> table.getColumn('role')?.setFilterValue(value) } content={ <> Designer Developer } /> col.getIsVisible()) .map((col) => col.id)} content={table .getAllColumns() .filter((column) => column.getCanHide()) .map((column) => ( column.toggleVisibility()} > {column.id} ))} /> {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {flexRender( header.column.columnDef.header, header.getContext(), )} ))} ))} {table.getRowModel().rows.length ? ( table.getRowModel().rows.map((row) => { return ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} ); }) ) : ( 검색 결과가 없습니다. )} table.setPageIndex(page - 1)} > table.setPageSize(Number(value))} > {(value) => `${value}개씩 보기`} {[5, 10, 20, 30, 40, 50].map((pageSize) => ( {pageSize} ))} ); } type Data = { name: string; status: 'active' | 'inactive'; role: string; 'last-active': string; }; const datas: Data[] = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; /* -----------------------------------------------------------------------------------------------*/ interface FilterSelectProps extends React.ComponentProps { triggerLabel: string; content: React.ReactNode; } const FilterSelect = ({ content, triggerLabel, ...props }: FilterSelectProps) => { return ( } style={{ width: 'unset' }} > {triggerLabel} {content} ); }; ```
# Box URL: /docs/components/box Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(layouts)/box/index.mdx 레이아웃과 스타일링을 위한 기본 컨테이너 컴포넌트입니다. 디자인 토큰을 활용한 간격, 색상, 크기 등의 속성을 제공합니다. ```tsx import { Box, Text } from '@vapor-ui/core'; export default function DefaultBox() { return ( Basic Box with padding, background, and border radius ); } ``` ## Property *** ### Display Types Box 컴포넌트는 다양한 디스플레이 타입을 지원하여 레이아웃을 유연하게 구성할 수 있습니다. ```tsx import { Box, Text, VStack } from '@vapor-ui/core'; export default function BoxDisplay() { return ( block Block element takes full width inline Inline }> flows with text like this flex Item 1 Item 2 Item 3 grid A B C ); } ``` ### Background Color Box 컴포넌트는 시맨틱 색상과 팔레트 색상을 모두 지원합니다. ```tsx import { Box, HStack } from '@vapor-ui/core'; export default function BoxBackground() { return ( Primary Secondary Success Warning Danger Gray Blue Green ); } ``` ### Spacing 패딩과 마진 속성을 사용하여 요소의 내부 및 외부 여백을 조절할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function BoxSpacing() { return ( padding Content with padding margin Content with margin paddingX/Y Horizontal padding marginX/Y Asymmetric margins ); } ``` ### Layout 플렉스박스 속성을 활용하여 다양한 레이아웃을 구성할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function BoxLayout() { return ( flexDirection row 1 2 3 column A B C justifyContent flex-start Start Items center Center Items space-between Space Between alignItems Small Medium Aligned ); } ``` ### Dimensions 너비와 높이를 설정하거나 최소/최대 크기 제약을 적용할 수 있습니다. ```tsx import { Box } from '@vapor-ui/core'; export default function BoxDimensions() { return ( 800x800 ); } ``` ### Visual Styles 테두리 둥글기, 투명도, 텍스트 정렬 등의 시각적 속성을 제어할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function BoxVisual() { return ( borderRadius Small Medium Large Extra Large opacity 30% 60% 90% 100% textAlign Left aligned Center aligned Right aligned overflow This text will be clipped when it overflows the container bounds because overflow is set to hidden. This text will show scrollbars when it overflows the container bounds because overflow is set to scroll. ); } ``` ## Props Table *** ### Box | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Flex URL: /docs/components/flex Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(layouts)/flex/index.mdx 플렉스박스 레이아웃을 쉽게 구현할 수 있는 컨테이너 컴포넌트입니다. Box 컴포넌트를 확장하여 플렉스 관련 기능을 제공합니다. ```tsx import { Box, Flex } from '@vapor-ui/core'; export default function DefaultFlex() { return ( Item 1 Item 2 Item 3 ); } ``` ## Examples *** ### Direction 플렉스 컨테이너의 주축 방향을 설정하여 항목들의 배치 방향을 제어할 수 있습니다. ```tsx import { Box, Flex, HStack, Text, VStack } from '@vapor-ui/core'; export default function FlexDirection() { return ( row 1 2 3 column 1 2 3 row-reverse 1 2 3 ); } ``` ## Props Table *** ### Flex | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `inline` | `boolean` | - | Displays the container as `inline-flex` instead of `flex`, so it sits inline with surrounding content. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Grid URL: /docs/components/grid Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(layouts)/grid/index.mdx 유연하고 강력한 CSS Grid 기반의 레이아웃 컴포넌트입니다 ```tsx import { Box, Grid } from '@vapor-ui/core'; export default function DefaultGrid() { return ( 1 2 3 4 5 6 ); } ``` ## Property *** ### Template Grid의 행과 열 템플릿을 설정하여 레이아웃 구조를 정의할 수 있습니다. ```tsx import { Box, Grid, HStack, Text, VStack } from '@vapor-ui/core'; export default function GridTemplate() { return ( templateColumns 200px 1fr 100px templateRows 60px 1fr 40px ); } ``` ### Flow Grid 아이템들의 자동 배치 방향을 설정할 수 있습니다. ```tsx import { Box, Grid, HStack, Text, VStack } from '@vapor-ui/core'; export default function GridFlow() { return ( row 1 2 3 4 5 column 1 2 3 4 5 ); } ``` ### Inline Grid를 인라인 요소로 표시할 수 있습니다. ```tsx import { Box, Grid, HStack, Text, VStack } from '@vapor-ui/core'; export default function GridInline() { return ( block (default) 1 2 inline 1 2 }> inline grid ); } ``` ### Span Grid 아이템이 차지할 행이나 열의 개수를 설정할 수 있습니다. ```tsx import { Box, Grid, HStack, Text, VStack } from '@vapor-ui/core'; export default function GridSpan() { return ( colSpan 1 Span 2 4 Span 3 8 rowSpan Row Span 2 2 3 5 6 ); } ``` ## Examples *** ### Layout Patterns 일반적인 레이아웃 패턴들을 Grid로 구현할 수 있습니다. ```tsx import { Box, Grid, HStack, Text, VStack } from '@vapor-ui/core'; export default function GridLayout() { return ( Dashboard Layout Header Sidebar Main Content Footer Card Layout Card 1 Card 2 Card 3 Card 4 ); } ``` ## Props Table *** ### Grid.Root | Prop | Type | Default | Description | | ----------------- | -------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `flow` | `row`, `column`, `row-dense`, `column-dense` | `row` | Direction in which items without an explicit position are placed, set as the `grid-auto-flow` value. The `-dense` values fill earlier gaps with later items. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `inline` | `boolean` | - | Displays the container as `inline-grid` instead of `grid`, so it sits inline with surrounding content. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `templateColumns` | `string` | - | Column tracks of the grid, set as the `grid-template-columns` value, such as `200px 1fr` or `repeat(3, 1fr)`. | | `templateRows` | `string` | - | Row tracks of the grid, set as the `grid-template-rows` value, such as `auto 1fr` or `repeat(3, 1fr)`. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Grid.Item | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `colSpan` | `string` | - | Columns the item occupies, set as the `grid-column` value, such as `span 2` or `1 / 3`. | | `rowSpan` | `string` | - | Rows the item occupies, set as the `grid-row` value, such as `span 2` or `1 / 3`. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # HStack URL: /docs/components/h-stack Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(layouts)/h-stack/index.mdx 수평으로 아이템들을 배치하는 레이아웃 컴포넌트입니다 ```tsx import { Box, HStack } from '@vapor-ui/core'; export default function DefaultHStack() { return ( Item 1 Item 2 Item 3 ); } ``` ## Property *** ### Reverse HStack의 아이템 순서를 역순으로 배치할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function HStackReverse() { return ( normal First Second Third reverse First Second Third ); } ``` ### Spacing HStack 아이템 간의 간격을 조정할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function HStackSpacing() { return ( $100 A B C $400 A B C $800 A B C ); } ``` ## Props Table *** ### HStack | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `inline` | `boolean` | - | Displays the container as `inline-flex` instead of `flex`, so it sits inline with surrounding content. | | `reverse` | `boolean` | - | Reverses the order of the children, setting `flex-direction` to `row-reverse`. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # VStack URL: /docs/components/v-stack Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(layouts)/v-stack/index.mdx 수직으로 아이템들을 배치하는 레이아웃 컴포넌트입니다 ```tsx import { Box, VStack } from '@vapor-ui/core'; export default function DefaultVStack() { return ( Item 1 Item 2 Item 3 ); } ``` ## Property *** ### Reverse VStack의 아이템 순서를 역순으로 배치할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function VStackReverse() { return ( normal First Second Third reverse First Second Third ); } ``` ### Spacing VStack 아이템 간의 간격을 조정할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function VStackSpacing() { return ( $100 A B C $400 A B C $800 A B C ); } ``` ### Alignment VStack 아이템들의 수평 정렬을 조정할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function VStackAlignment() { return ( start Short Medium Width Tiny center Short Medium Width Tiny end Short Medium Width Tiny ); } ``` ### Justify Content VStack 아이템들의 수직 분산을 조정할 수 있습니다. ```tsx import { Box, HStack, Text, VStack } from '@vapor-ui/core'; export default function VStackJustify() { return ( flex-start A B C center A B C space-between A B C ); } ``` ## Props Table *** ### VStack | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `inline` | `boolean` | - | Displays the container as `inline-flex` instead of `flex`, so it sits inline with surrounding content. | | `reverse` | `boolean` | - | Reverses the order of the children, setting `flex-direction` to `column-reverse`. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Avatar URL: /docs/components/avatar Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/avatar/index.mdx Avatar는 사용자가 설정한 프로필 이미지 혹은 텍스트를 UI상에 나타냅니다. ```tsx import { Avatar } from '@vapor-ui/core'; import { VAPOR_LOGO_URL } from '~/constants/image-urls'; export default function DefaultAvatar() { return ; } ``` ## Property *** ### Shape Avatar의 모양을 설정합니다. ```tsx import { Avatar, HStack, Text, VStack } from '@vapor-ui/core'; import { VAPOR_LOGO_URL } from '~/constants/image-urls'; export default function AvatarShape() { return ( square circle ); } ``` ### Size Avatar의 크기를 설정합니다. ```tsx import { Avatar, HStack, Text, VStack } from '@vapor-ui/core'; import { VAPOR_LOGO_URL } from '~/constants/image-urls'; export default function AvatarSize() { return ( sm md lg xl ); } ``` ## Examples *** ### Fallback 이미지가 없거나 로드에 실패한 경우, alt 텍스트의 첫 글자가 자동으로 표시됩니다. 배경색은 alt 문자열을 기반으로 결정됩니다. ```tsx import { Avatar, HStack } from '@vapor-ui/core'; export default function AvatarFallback() { return ( ); } ``` ### Custom Fallback FallbackPrimitive에 children을 전달하여 커스텀 fallback 콘텐츠를 표시합니다. ```tsx import { Avatar, HStack, Text, VStack } from '@vapor-ui/core'; export default function AvatarCustomFallback() { return ( auto initial custom text JD ); } ``` ### Custom Image `children`으로 `Avatar.ImagePrimitive`와 `Avatar.FallbackPrimitive`를 전달하면 각 슬롯에 직접 props를 적용할 수 있습니다. `src`, `alt`, `crossOrigin` 등 이미지 관련 props는 `Avatar.Root`에 전달하면 내부 Primitive로 자동 전달됩니다. ```tsx import { Avatar, HStack, Text, VStack } from '@vapor-ui/core'; const IMAGE_URL = 'https://avatars.githubusercontent.com/u/217160984?v=4'; export default function AvatarCustomImage() { return ( ImagePrimitive FallbackPrimitive JD ); } ``` ## Props Table *** ### Avatar.Root | Prop | Type | Default | Description | | ----------------------- | --------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `shape` | `circle`, `square` | `square` | Corner style of the avatar. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the avatar, controlling width, height, corner radius, and the typography of the fallback. | | `onLoadingStatusChange` | `function` | - | Callback fired when the loading status changes. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `fallbackElement` | `ReactElement` | - | Replaces the default `Avatar.FallbackPrimitive`. Ignored when `children` are given. | | `imageElement` | `ReactElement` | - | Replaces the default `Avatar.ImagePrimitive`. Ignored when `children` are given. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `delay` | `number` | `0` | How long to wait before showing the fallback. Specified in milliseconds. | | `keepMounted` | `boolean` | `false` | Whether the image element stays mounted and loads in place instead of being preloaded.
Supports `loading="lazy"` and optimized image components such as `next/image`. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Avatar.ImagePrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Avatar.FallbackPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Badge URL: /docs/components/badge Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/badge/index.mdx Badge는 이미지, 컨텐츠 등의 상태 또는 분류를 시각적으로 표시합니다. ```tsx import { Badge } from '@vapor-ui/core'; export default function DefaultBadge() { return New; } ``` ## Property *** ### ColorPalette Badge의 색상을 설정합니다. ```tsx import { Badge, HStack, Text, VStack } from '@vapor-ui/core'; export default function BadgeColor() { return ( primary New hint New danger New success New warning New contrast New ); } ``` ### Shape Badge의 모양을 설정합니다. ```tsx import { Badge, HStack, Text, VStack } from '@vapor-ui/core'; export default function BadgeShape() { return ( square New pill New ); } ``` ### Size Badge의 크기를 설정합니다. ```tsx import { Badge, HStack, Text, VStack } from '@vapor-ui/core'; export default function BadgeSize() { return ( sm New md New lg New ); } ``` ## Props Table *** ### Badge | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `colorPalette` | `hint`, `primary`, `success`, `warning`, `danger`, `contrast` | `primary` | Color palette of the badge, applied to its background and text. | | `shape` | `square`, `pill` | `square` | Corner style of the badge. | | `size` | `sm`, `md`, `lg` | `md` | Size of the badge, controlling height, padding, and typography. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Breadcrumb URL: /docs/components/breadcrumb Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/breadcrumb/index.mdx 사용자가 현재 페이지의 위치를 파악하고 이전 페이지로 쉽게 이동할 수 있도록 도와주는 네비게이션 컴포넌트입니다. ```tsx import { Breadcrumb } from '@vapor-ui/core'; export default function DefaultBreadcrumb() { return ( Home Products Details ); } ``` ## Examples *** ### With Ellipsis 긴 네비게이션 경로에서 중간 단계를 생략 표시로 나타낸 패턴입니다. ```tsx import { Breadcrumb } from '@vapor-ui/core'; export default function BreadcrumbEllipsis() { return ( Home Category Subcategory Current Page ); } ``` ### Composition Pattern Breadcrumb 컴포넌트의 다양한 구성 패턴입니다. ```tsx import { Breadcrumb, Text, VStack } from '@vapor-ui/core'; import { ChevronRightOutlineIcon, HomeIcon } from '@vapor-ui/icons'; export default function BreadcrumbComposition() { return ( Basic Home Products Details Custom Separator Home Products Details With Icon Home Dashboard Settings ); } ``` ## Property *** ### Current 현재 페이지를 나타내는 링크의 상태를 설정할 수 있습니다. ```tsx import { Breadcrumb, Text, VStack } from '@vapor-ui/core'; export default function BreadcrumbCurrent() { return ( Normal Links Home Products Details With Current Page Home Products Details ); } ``` ### Size Breadcrumb의 크기를 설정합니다. ```tsx import { Breadcrumb, HStack, Text, VStack } from '@vapor-ui/core'; export default function BreadcrumbSize() { return ( sm Home Products Details md Home Products Details lg Home Products Details xl Home Products Details ); } ``` ## Props Table *** ### Breadcrumb.Root | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the breadcrumb, controlling the typography of the links and the size of the separator and ellipsis icons. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Breadcrumb.RootPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the breadcrumb, controlling the typography of the links and the size of the separator and ellipsis icons. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Breadcrumb.ListPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Breadcrumb.Item | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `current` | `boolean` | `false` | Marks the link as the current page, applying the active color and setting `aria-current="page"` and `aria-disabled` on the `<a>` element. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Breadcrumb.ItemPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Breadcrumb.LinkPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `current` | `boolean` | `false` | Marks the link as the current page, applying the active color and setting `aria-current="page"` and `aria-disabled` on the `<a>` element. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Breadcrumb.Separator | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown as the separator, such as a chevron icon. Replaces the default slash icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Breadcrumb.Ellipsis | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown for the collapsed items. Replaces the default more icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Breadcrumb.EllipsisPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown for the collapsed items. Replaces the default more icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Button URL: /docs/components/button Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/button/index.mdx Button은 사용자가 주요 작업을 수행하도록 돕는 핵심 상호작용 요소입니다. ```tsx import { Button } from '@vapor-ui/core'; export default function DefaultButton() { return ; } ``` ## Property *** ### Variant Button의 시각적 스타일을 설정합니다. ```tsx import { Button, HStack, Text, VStack } from '@vapor-ui/core'; export default function ButtonVariant() { return ( fill outline ghost ); } ``` ### ColorPalette Button의 역할에 따른 색상을 설정합니다. ```tsx import { Button, HStack, Text, VStack } from '@vapor-ui/core'; export default function ButtonColor() { return ( primary secondary success warning danger contrast ); } ``` ### Disabled Button의 비활성화 상태를 설정합니다. ```tsx import { Button, HStack, Text, VStack } from '@vapor-ui/core'; export default function ButtonDisabled() { return ( enabled disabled ); } ``` ### Size Button의 크기를 설정합니다. ```tsx import { Button, HStack, Text, VStack } from '@vapor-ui/core'; export default function ButtonSize() { return ( sm md lg xl ); } ``` ## Examples *** ### Button with Icon Button의 역할을 직관적으로 표현하기 위해 아이콘과 함께 사용합니다. ```tsx import { Button, HStack } from '@vapor-ui/core'; import { CheckCircleIcon, ChevronRightOutlineIcon } from '@vapor-ui/icons'; export default function ButtonWithIcon() { return ( ); } ``` ## Props Table *** ### Button | Prop | Type | Default | Description | | ----------------------- | ------------------------------------------------------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `colorPalette` | `primary`, `secondary`, `success`, `warning`, `danger`, `contrast` | `primary` | Color palette of the button, applied to its background, text, and border according to `variant`. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the button, controlling height, padding, and typography. | | `variant` | `fill`, `outline`, `ghost` | `fill` | Visual style of the button. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `focusableWhenDisabled` | `boolean` | `false` | Whether the button should be focusable when disabled. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Callout URL: /docs/components/callout Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/callout/index.mdx Callout은 중요한 정보를 시각적으로 강조하여 사용자에게 전달하는 메시지 컴포넌트입니다. ```tsx import { Callout } from '@vapor-ui/core'; import { InfoCircleOutlineIcon } from '@vapor-ui/icons'; export default function DefaultCallout() { return ( Your changes have been saved successfully. ); } ``` ## Examples *** ### Callout with Icon Callout의 역할을 직관적으로 표현하기 위해 아이콘과 함께 사용합니다. ```tsx import { Callout, VStack } from '@vapor-ui/core'; import { CheckCircleIcon, HeartIcon, InfoCircleOutlineIcon } from '@vapor-ui/icons'; export default function CalloutWithIcon() { return ( Task completed successfully Please review your settings New notification available ); } ``` ## Property *** ### ColorPalette Callout의 역할에 따른 색상을 설정합니다. ```tsx import { Callout, Text, VStack } from '@vapor-ui/core'; export default function CalloutColor() { return ( primary Your changes have been saved successfully. success Your changes have been saved successfully. warning Your changes have been saved successfully. danger Your changes have been saved successfully. hint Your changes have been saved successfully. contrast Your changes have been saved successfully. ); } ``` ## Props Table *** ### Callout.Root | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `colorPalette` | `hint`, `primary`, `success`, `warning`, `danger`, `contrast` | `primary` | Color palette of the callout, applied to its border, background, and text. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Callout.Icon | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Card URL: /docs/components/card Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/card/index.mdx Card는 이미지와 텍스트, 일부 기능 버튼을 포함한 컨테이너로 콘텐츠를 제공합니다. ```tsx import { Button, Card, HStack, Text, VStack } from '@vapor-ui/core'; export default function DefaultCard() { return ( } typography="heading5"> Project Settings Configure your project settings and preferences. ); } ``` ## Examples *** ### Layout 상황에 따라, 일부 영역을 생략하여 Card를 구성할 수 있습니다. ```tsx import { Card, HStack, Text, VStack } from '@vapor-ui/core'; export default function CardLayout() { return ( Body only A simple card with content only. Body + Footer Card content goes here. Updated 2 hours ago Header + Body } typography="heading6"> Notifications You have 3 unread messages. ); } ``` ## Props Table *** ### Card.Root | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Card.Header | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Card.Body | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Card.Footer | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Checkbox URL: /docs/components/checkbox Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/checkbox/index.mdx Checkbox는 여러 항목 중 복수 선택을 가능하게 하는 입력 컴포넌트입니다. ```tsx import { Checkbox, HStack, Text } from '@vapor-ui/core'; export default function DefaultCheckbox() { return ( } typography="body2"> I agree to the terms and conditions ); } ``` ## Property *** ### Indeterminate Checkbox의 혼합 상태 여부를 설정합니다. ```tsx import { Checkbox, HStack, Text, VStack } from '@vapor-ui/core'; export default function CheckboxIndeterminate() { return ( unchecked } typography="body2"> Select all indeterminate } typography="body2"> Select all checked } typography="body2"> Select all ); } ``` ### Disabled Checkbox의 비활성화 상태를 설정합니다. ```tsx import { Checkbox, HStack, Text, VStack } from '@vapor-ui/core'; export default function CheckboxDisabled() { return ( disabled } typography="body2"> Remember me disabled checked } typography="body2"> Remember me ); } ``` ### Invalid Checkbox의 유효하지 않음 상태를 설정합니다. ```tsx import { Checkbox, HStack, Text, VStack } from '@vapor-ui/core'; export default function CheckboxInvalid() { return ( invalid } typography="body2"> Accept terms invalid checked } typography="body2"> Accept terms ); } ``` ### Read Only Checkbox의 읽기 전용 상태를 설정합니다. ```tsx import { Checkbox, HStack, Text, VStack } from '@vapor-ui/core'; export default function CheckboxReadOnly() { return ( unchecked checked indeterminate ); } ``` ### Size Checkbox의 크기를 설정합니다. ```tsx import { Checkbox, HStack, Text, VStack } from '@vapor-ui/core'; export default function CheckboxSize() { return ( md } typography="body2"> Remember me lg } typography="body2"> Remember me ); } ``` ## Props Table *** ### Checkbox.Root | Prop | Type | Default | Description | | ----------------- | --------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid` | `boolean` | `false` | Marks the checkbox as invalid, applying error styles. Sets `aria-invalid` on the `<span>` element. | | `size` | `md`, `lg` | `md` | Size of the checkbox, controlling its width, height, and corner radius, and the size of its check mark. | | `checked` | `boolean` | - | Whether the checkbox is currently ticked.

To render an uncontrolled checkbox, use the `defaultChecked` prop instead. | | `defaultChecked` | `boolean` | `false` | Whether the checkbox is initially ticked.

To render a controlled checkbox, use the `checked` prop instead. | | `onCheckedChange` | `function` | - | Event handler called when the checkbox is ticked or unticked. | | `value` | `string` | - | The checkbox's value. Identifies it within a [Checkbox Group](https://base-ui.com/react/components/checkbox-group), falling back to `name` when omitted.
When submitting a form, a checked box submits `value`; with no `value`, it submits the native "on". | | `children` | `ReactNode` | - | Element shown inside the checkbox in place of the default `Checkbox.IndicatorPrimitive`, such as a `Checkbox.IndicatorPrimitive` with custom props. Anything other than a single element is ignored and the default indicator is shown. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `form` | `string` | - | Identifies the form that owns the hidden input.
Useful when the checkbox is rendered outside the form. | | `id` | `string` | - | The id of the input element. | | `indeterminate` | `boolean` | `false` | Whether the checkbox is in a mixed state: neither ticked, nor unticked. | | `inputRef` | `React.Ref` | - | A ref to access the hidden `<input>` element. | | `name` | `string` | - | Identifies the field when a form is submitted. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `parent` | `boolean` | `false` | Whether the checkbox controls a group of child checkboxes.

Must be used in a [Checkbox Group](https://base-ui.com/react/components/checkbox-group). | | `readOnly` | `boolean` | `false` | Whether the user should be unable to tick or untick the checkbox. | | `required` | `boolean` | `false` | Whether the user must tick the checkbox before submitting a form. | | `uncheckedValue` | `string` | - | The value submitted with the form when the checkbox is unchecked.
By default, unchecked checkboxes do not submit any value, matching native checkbox behavior. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Checkbox.IndicatorPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown in place of the default check mark or dash, such as an icon component. The element receives a `width` and `height` of `100%`. Anything other than a single element is ignored and the default icon is shown. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | `true` | Whether to keep the element in the DOM when the checkbox is not checked. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Collapsible URL: /docs/components/collapsible Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/collapsible/index.mdx Collapsible은 콘텐츠를 접었다 펼칠 수 있는 대화형 컴포넌트입니다. 아코디언이나 확장 가능한 섹션을 구현할 때 사용합니다. ```tsx import { Collapsible, Text, VStack } from '@vapor-ui/core'; import { ChevronRightOutlineIcon } from '@vapor-ui/icons'; export default function DefaultCollapsible() { return ( Settings Account Notifications Privacy ); } ``` ## Property *** ### Open State `defaultOpen`으로 초기 열림 상태를 설정하거나, `open`과 `onOpenChange`로 제어 모드로 사용합니다. ```tsx import { useState } from 'react'; import { Button, Collapsible, HStack, Text, VStack } from '@vapor-ui/core'; export default function CollapsibleOpenState() { const [open, setOpen] = useState(true); return ( defaultOpen FAQ Section This panel starts open and manages its own state. controlled Release Notes This panel is controlled externally via state. ); } ``` ### Disabled Collapsible의 비활성화 상태를 설정합니다. ```tsx import { Collapsible, Text, VStack } from '@vapor-ui/core'; import { ChevronRightOutlineIcon } from '@vapor-ui/icons'; export default function CollapsibleDisabled() { return ( enabled Advanced Options Configure advanced settings for your project. disabled Advanced Options Configure advanced settings for your project. ); } ``` ### Keep Mounted `keepMounted`를 사용하면 패널이 닫힌 상태에서도 DOM에 유지됩니다. ```tsx import { Collapsible, HStack, Text, VStack } from '@vapor-ui/core'; import { ChevronRightOutlineIcon } from '@vapor-ui/icons'; export default function CollapsibleKeepMounted() { return ( default Help Section Removed from DOM when closed. keepMounted Help Section Stays in DOM when closed. ); } ``` ## Props Table *** ### Collapsible.Root | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultOpen` | `boolean` | `false` | Whether the collapsible panel is initially open.

To render a controlled collapsible, use the `open` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the panel is opened or closed. | | `open` | `boolean` | - | Whether the collapsible panel is currently open.

To render an uncontrolled collapsible, use the `defaultOpen` prop instead. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Collapsible.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Collapsible.Panel | Prop | Type | Default | Description | | ------------------ | --------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `hiddenUntilFound` | `boolean` | `false` | Allows the browser's built-in page search to find and expand the panel contents.

Overrides the `keepMounted` prop and uses `hidden="until-found"`
to hide the element without removing it from the DOM. | | `keepMounted` | `boolean` | `false` | Whether to keep the element in the DOM while the panel is hidden.
This prop is ignored when `hiddenUntilFound` is used. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Dialog URL: /docs/components/dialog Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/dialog/index.mdx Dialog는 페이지 위에 모달 형태로 정보를 표시하거나 작업을 수행하도록 하는 컴포넌트입니다. ```tsx import { Button, Dialog } from '@vapor-ui/core'; export default function DefaultDialog() { return ( }>클릭 알림 여기에 다이얼로그 본문 내용이 들어갑니다. 확인} /> ); } ``` ## Property *** ### Size Dialog의 크기를 설정합니다. ```tsx import { Button, Dialog, HStack, Text, VStack } from '@vapor-ui/core'; export default function DialogSize() { return ( md Medium Dialog} /> Medium Size Medium 크기의 다이얼로그입니다. 취소} /> 확인} /> lg Large Dialog} /> Large Size Large 크기의 다이얼로그입니다. 취소} /> 확인} /> xl Extra Large Dialog} /> Extra Large Size Extra Large 크기의 다이얼로그입니다. 취소} /> 확인} /> ); } ``` ### Modal Behavior Dialog의 모달 동작을 설정합니다. ```tsx import { Button, Dialog, HStack, Text, VStack } from '@vapor-ui/core'; export default function DialogModal() { return ( modal Modal Dialog} /> Modal Dialog 포커스가 다이얼로그 내부에 제한됩니다. 확인} /> non-modal Non-Modal Dialog} /> Non-Modal Dialog 배경의 다른 요소들과 상호작용할 수 있습니다. 확인} /> ); } ``` ## Examples *** ### Custom Usage Dialog 컴포넌트의 다양한 구성 패턴입니다. ```tsx import { Button, Dialog } from '@vapor-ui/core'; export default function Flexible() { return ( 확인 다이얼로그} /> 작업 확인 이 작업을 진행하시겠습니까? 이 작업은 되돌릴 수 없습니다. 취소} /> 삭제} /> ); } ``` ### Custom Overlay `Dialog.PortalPrimitive`, `Dialog.OverlayPrimitive`, `Dialog.PopupPrimitive`를 직접 조합하면 오버레이 스타일 등 레이어 구조를 제어할 수 있습니다. ```tsx import { Button, Dialog } from '@vapor-ui/core'; export default function DialogCustomOverlay() { return ( 열기} /> 커스텀 오버레이 Primitive를 직접 조합해 오버레이의 스타일을 제어한 예시입니다. 닫기} /> ); } ``` ## Props Table *** ### Dialog.Root | Prop | Type | Default | Description | | ---------------------- | ---------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | `md`, `lg`, `xl` | `md` | Width of the dialog popup. | | `defaultOpen` | `boolean` | `false` | Whether the dialog is initially open.

To render a controlled dialog, use the `open` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the dialog is opened or closed. | | `open` | `boolean` | - | Whether the dialog is currently open. | | `closeOnClickOverlay` | `boolean` | `true` | When `true`, clicking the overlay closes the dialog. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the dialog.
Call this after any externally controlled closing animation finishes.
- `close`: Closes the dialog imperatively when called. | | `children` | `ReactNode`, `function` | - | The content of the dialog.
This can be a regular React node or a render function that receives the `payload` of the active trigger. | | `defaultTriggerId` | `string`, `null` | - | ID of the trigger that the dialog is associated with.
This is useful in conjunction with the `defaultOpen` prop to create an initially open dialog. | | `handle` | `DialogHandle` | - | A handle to associate the dialog with a trigger.
If specified, allows external triggers to control the dialog's open state.
Can be created with the Dialog.createHandle() method. | | `modal` | `boolean`, `trap-focus` | `true` | Determines if the dialog enters a modal state when open.
- `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled.
- `false`: user interaction with the rest of the document is allowed.
- `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled.

When `modal` is `true` or `'trap-focus'`, render `<Dialog.Close>` inside `<Dialog.Popup>` so
touch screen readers can escape the popup. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the dialog is opened or closed. | | `triggerId` | `string`, `null` | - | ID of the trigger that the dialog is associated with.
This is useful in conjunction with the `open` prop to create a controlled dialog.
There's no need to specify this prop when the dialog is uncontrolled (that is, when the `open` prop is not set). | ### Dialog.Popup | Prop | Type | Default | Description | | ---------------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `overlayElement` | `ReactElement` | - | Replaces the default `Dialog.OverlayPrimitive`. Use to change the backdrop. | | `portalElement` | `ReactElement` | - | Replaces the default `Dialog.PortalPrimitive`. Use to change the portal container. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is opened.
By default, focus moves to the first tabbable element inside the popup, except when the dialog
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Dialog.PortalPrimitive | Prop | Type | Default | Description | | ------------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `keepMounted` | `boolean` | `false` | Whether to keep the portal mounted in the DOM while the popup is hidden. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Dialog.OverlayPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `forceRender` | `boolean` | `false` | Whether the backdrop is forced to render even when nested. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Dialog.PopupPrimitive | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is opened.
By default, focus moves to the first tabbable element inside the popup, except when the dialog
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Dialog.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `handle` | `DialogHandle` | - | A handle to associate the trigger with a dialog.
Can be created with the Dialog.createHandle() method. | | `id` | `string` | - | ID of the trigger. In addition to being forwarded to the rendered element,
it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot `triggerId` prop). | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `payload` | `unknown` | - | A payload to pass to the dialog when it is opened. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Dialog.Close | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Dialog.Title | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Dialog.Description | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Dialog.Header | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Dialog.Body | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Dialog.Footer | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Field URL: /docs/components/field Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/field/index.mdx Field는 폼 요소들을 감싸는 컨테이너 컴포넌트로, 라벨, 설명, 에러 메시지, 성공 메시지 등을 제공합니다. ```tsx 'use client'; import { Field, TextInput } from '@vapor-ui/core'; export default function DefaultField() { return ( Email We'll never share your email. ); } ``` ## Examples *** ### With Description Field에 대한 추가 설명을 표시합니다. ```tsx 'use client'; import { Field, TextInput, VStack } from '@vapor-ui/core'; export default function FieldDescription() { return ( Username Username This will be your public display name. ); } ``` ### Error and Success `Field.Error`와 `Field.Success`를 사용하여 유효성 검사 결과를 표시합니다. ```tsx 'use client'; import { Field, TextInput, VStack } from '@vapor-ui/core'; export default function FieldError() { return ( Email Please enter a valid email address. Email Email is valid. ); } ``` ### Required 필수 Field와 선택 Field를 구분하여 표시합니다. ```tsx 'use client'; import { Field, Text, TextInput, VStack } from '@vapor-ui/core'; export default function FieldRequired() { return ( 필수 입력 필드 이 필드는 반드시 입력해야 하는 필수 항목입니다. 이 필드는 필수 입력 항목입니다. 입력이 완료되었습니다. {/* Optional Field */} 선택 입력 필드{' '} (선택사항) 이 필드는 선택적으로 입력할 수 있습니다. ); } ``` ### Disabled disabled 속성을 사용하여 비활성화된 Field를 만들 수 있습니다. ```tsx 'use client'; import { Field, Text, TextInput, VStack } from '@vapor-ui/core'; export default function FieldDisabled() { return ( enabled Email Enter your email address. disabled Email Enter your email address. ); } ``` ### With RadioGroup RadioGroup과 Field를 함께 사용합니다. `Field.Item`을 사용하여 각 Radio 옵션을 라벨과 함께 그룹화할 수 있습니다. ```tsx 'use client'; import { Field, Radio, RadioGroup, VStack } from '@vapor-ui/core'; export default function FieldRadioGroup() { return ( 성별 남성 여성 기타 개인정보 보호를 위해 선택사항입니다. ); } ``` ### With Form Elements TextInput, Checkbox, Switch, Select 등 다양한 폼 요소와 함께 사용합니다. ```tsx 'use client'; import { Checkbox, Field, Select, Switch, TextInput, VStack } from '@vapor-ui/core'; export default function FieldWithInputs() { return ( Email Your primary contact email. Subscribe to newsletter Get the latest updates in your inbox. Push notifications Receive alerts on your device. 국가 {countries.map((country) => ( {country.label} ))} Select your country of residence. ); } const countries = [ { label: '대한민국', value: 'kr' }, { label: '미국', value: 'us' }, { label: '일본', value: 'jp' }, { label: '중국', value: 'cn' }, ]; ``` ## Property *** ### Validation `validationMode`를 통해 유효성 검사 타이밍을 설정합니다. `match` prop으로 특정 에러 타입에 대한 메시지를 표시합니다. ```tsx 'use client'; import { Field, TextInput, VStack } from '@vapor-ui/core'; export default function FieldValidation() { return ( Email Validated when you leave the field. Email is required. Please enter a valid email. Email looks good. Password Validated as you type. Minimum 8 characters. Password is required. Password must be at least 8 characters. Password is strong. ); } ``` ### Disabled Field의 비활성화 상태를 설정합니다. ```tsx 'use client'; import { Field, Text, TextInput, VStack } from '@vapor-ui/core'; export default function FieldDisabled() { return ( enabled Email Enter your email address. disabled Email Enter your email address. ); } ``` ## Props Table *** ### Field.Root | Prop | Type | Default | Description | | ------------------------ | --------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `validate`: Validates the field when called. | | `dirty` | `boolean` | - | Whether the field's value has been changed from its initial value.
Useful when the field state is controlled by an external library. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction.
Takes precedence over the `disabled` prop on the `<Field.Control>` component. | | `invalid` | `boolean` | - | Whether the field is invalid.
Useful when the field state is controlled by an external library. | | `name` | `string` | - | Identifies the field when a form is submitted.
Takes precedence over the `name` prop on the `<Field.Control>` component. | | `touched` | `boolean` | - | Whether the field has been touched.
Useful when the field state is controlled by an external library. | | `validate` | `function` | - | A function for custom validation. Return a string or an array of strings with
the error message(s) if the value is invalid. Returning nothing, `null`, an empty
string, or an empty array means the value is valid.
Asynchronous functions are supported, but they do not prevent form submission
when using `validationMode="onSubmit"`. | | `validationDebounceTime` | `number` | `0` | How long to wait between `validate` callbacks if
`validationMode="onChange"` is used. Specified in milliseconds. | | `validationMode` | `onBlur`, `onChange`, `onSubmit` | `onSubmit` | Determines when the field should be validated.
This takes precedence over the `validationMode` prop on `<Form>`.

- `onSubmit`: triggers validation when the form is submitted, and re-validates on change after submission.
- `onBlur`: triggers validation when the control loses focus.
- `onChange`: triggers validation on every change to the control value. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Field.Label | Prop | Type | Default | Description | | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `foreground` | `hint`, `normal`, `white`, `primary-100`, `primary-200`, `primary`, `secondary-100`, `secondary-200`, `secondary`, `success-100`, `success-200`, `success`, `warning-100`, `warning-200`, `warning`, `danger-100`, `danger-200`, `danger`, `hint-100`, `hint-200`, `contrast-100`, `contrast-200`, `contrast`, `primary-strong`, `success-strong`, `warning-strong`, `danger-strong`, `normal-100`, `normal-200`, `inverse`, `staticWhite`, `staticBlack` | `secondary` | Text color of the label. | | `typography` | `body1`, `display1`, `display2`, `display3`, `display4`, `heading1`, `heading2`, `heading3`, `heading4`, `heading5`, `heading6`, `subtitle1`, `subtitle2`, `body2`, `body3`, `body4`, `code1`, `code2` | `body2` | Typography style of the label text. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `nativeLabel` | `boolean` | `true` | Whether the component renders a native `<label>` element when replacing it via the `render` prop.
Set to `false` if the rendered element is not a label (for example, `<div>`).

This is useful to avoid inheriting label behaviors on `<button>` controls (such as `<Select.Trigger>` and `<Combobox.Trigger>`), including avoiding `:hover` on the button when hovering the label, and preventing clicks on the label from firing on the button. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Field.Description | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Field.Error | Prop | Type | Default | Description | | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `match` | `boolean`, `badInput`, `customError`, `patternMismatch`, `rangeOverflow`, `rangeUnderflow`, `stepMismatch`, `tooLong`, `tooShort`, `typeMismatch`, `valueMissing` | - | Shows the message only for the given [ValidityState](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState) key, such as `valueMissing` or `typeMismatch`. Set to `true` to always show it, letting an external library control its visibility. When omitted, the message shows whenever the field is invalid. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Field.Success | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `match` | `boolean`, `valid` | `valid` | Controls when the message is shown. With `'valid'`, it shows once the field passes validation. Set to `true` to always show it, letting an external library control its visibility. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Field.Item | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the wrapped control should ignore user interaction.
The `disabled` prop on `<Field.Root>` takes precedence over this. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # FloatingBar URL: /docs/components/floating-bar Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/floating-bar/index.mdx FloatingBar는 하단에 고정되어 주요 액션을 포함하는 컴포넌트입니다. ```tsx import { FloatingBar } from '@vapor-ui/core'; export default function DefaultFloatingBar() { return ( Open Floating Bar This is the floating bar content. ); } ``` ## Examples *** ### Actions FloatingBar는 다양한 액션 요소를 담을 수 있습니다. ```tsx import { Box, Button, FloatingBar } from '@vapor-ui/core'; export default function FloatingBarWithActions() { return ( }>Open FloatingBar ); } ``` ### Controlled FloatingBar는 제어 형태로 사용되어, 여러 상태를 동시에 관리할 수 있습니다. ```tsx import { useState } from 'react'; import { Badge, Box, Button, Checkbox, Field, FloatingBar, IconButton, Text, VStack, } from '@vapor-ui/core'; import { CloseOutlineIcon } from '@vapor-ui/icons'; const options = [ { id: 'item1', label: 'First Item', defaultChecked: false }, { id: 'item2', label: 'Second Item', defaultChecked: false }, { id: 'item3', label: 'Third Item', defaultChecked: false }, ]; export default function FloatingBarControlled() { const [selectedItems, setSelectedItems] = useState(() => Object.fromEntries(options.map((option) => [option.id, option.defaultChecked])), ); const selectedCount = Object.values(selectedItems).filter(Boolean).length; const [open, setOpen] = useState(selectedCount > 0); const handleItemChange = (itemId: string, isChecked: boolean) => { setSelectedItems((prev) => { const newSelectedItems = { ...prev, [itemId]: isChecked }; const newSelectedCount = Object.values(newSelectedItems).filter(Boolean).length; setOpen(newSelectedCount > 0); return newSelectedItems; }); }; const handleSelectAll = () => { setSelectedItems(Object.fromEntries(options.map((option) => [option.id, true]))); setOpen(true); }; const handleClearAll = () => { setSelectedItems(Object.fromEntries(options.map((option) => [option.id, false]))); setOpen(false); }; return ( <> } $css={{ marginBottom: '$200' }}> Select options below to see the FloatingBar. {options.map((option) => ( handleItemChange(option.id, checked)} /> {option.label} ))} {selectedCount} Selected } > ); } ``` ## Props Table *** ### FloatingBar.Root | Prop | Type | Default | Description | | ---------------------- | --------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultOpen` | `boolean` | `false` | Whether the popover is initially open.

To render a controlled popover, use the `open` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the popover is opened or closed. | | `open` | `boolean` | - | Whether the popover is currently open. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the popover.
Call this after any externally controlled closing animation finishes.
- `close`: Closes the popover imperatively when called. | | `children` | `ReactNode`, `function` | - | The content of the popover.
This can be a regular React node or a render function that receives the `payload` of the active trigger. | | `defaultTriggerId` | `string`, `null` | - | ID of the trigger that the popover is associated with.
This is useful in conjunction with the `defaultOpen` prop to create an initially open popover. | | `handle` | `PopoverHandle` | - | A handle to associate the popover with a trigger.
If specified, allows external triggers to control the popover's open state. | | `modal` | `boolean`, `trap-focus` | `false` | Determines if the popover enters a modal state when open.
- `true`: user interaction is limited to the popover: document page scroll is locked, and pointer interactions on outside elements are disabled.
- `false`: user interaction with the rest of the document is allowed.
- `'trap-focus'`: focus is trapped inside the popover, but document page scroll is not locked and pointer interactions outside of it remain enabled.

On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior.

When `modal` is `true`, focus trapping is enabled only if `<Popover.Close>` is rendered
inside `<Popover.Popup>`. It can be visually hidden with your own CSS if needed, such as
Tailwind's `sr-only` utility.

When `modal` is `'trap-focus'`, render `<Popover.Close>` inside `<Popover.Popup>` so touch
screen readers can escape the popup. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the popover is opened or closed. | | `triggerId` | `string`, `null` | - | ID of the trigger that the popover is associated with.
This is useful in conjunction with the `open` prop to create a controlled popover.
There's no need to specify this prop when the popover is uncontrolled (that is, when the `open` prop is not set). | ### FloatingBar.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeDelay` | `number` | `0` | How long to wait before closing the popover that was opened on hover.
Specified in milliseconds.

Requires the `openOnHover` prop. | | `delay` | `number` | `300` | How long to wait before the popover may be opened on hover. Specified in milliseconds.

Requires the `openOnHover` prop. | | `handle` | `PopoverHandle` | - | A handle to associate the trigger with a popover. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `openOnHover` | `boolean` | `false` | Whether the popover should also open when the trigger is hovered. | | `payload` | `unknown` | - | A payload to pass to the popover when it is opened. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### FloatingBar.Close | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### FloatingBar.Popup | Prop | Type | Default | Description | | --------------- | ------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `portalElement` | `ReactElement` | - | Replaces the default `FloatingBar.PortalPrimitive`. Use to change the portal container. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is opened.
By default, focus moves to the first tabbable element inside the popup, except when the popover
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### FloatingBar.PortalPrimitive | Prop | Type | Default | Description | | ------------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `keepMounted` | `boolean` | `false` | Whether to keep the portal mounted in the DOM while the popup is hidden. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### FloatingBar.PositionerPrimitive | Prop | Type | Default | Description | | ----------------------- | ----------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `align` | `center`, `end`, `start` | `center` | How to align the popup relative to the specified side. | | `alignOffset` | `number`, `function` | `0` | Additional offset along the alignment axis in pixels.
Also accepts a function that returns the offset to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `anchor` | `Element`, `VirtualElement`, `React.RefObject`, `function`, `null` | - | An element to position the popup against.
By default, the popup will be positioned against the trigger. | | `arrowPadding` | `number` | `5` | Minimum distance to maintain between the arrow and the edges of the popup.

Use it to prevent the arrow element from hanging out of the rounded corners of a popup. | | `collisionAvoidance` | `CollisionAvoidance` | - | Determines how to handle collisions when positioning the popup.

`side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):
- `'flip'`: keep the requested side when it fits; otherwise try the opposite side
(`top` and `bottom`, or `left` and `right`).
- `'shift'`: never change side; keep the requested side and move the popup within
the clipping boundary so it stays visible.
- `'none'`: do not correct side-axis overflow.

`align` controls overflow on the alignment axis (`start`/`center`/`end`):
- `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
- `'shift'`: keep side and requested alignment, then nudge the popup along the
alignment axis to fit.
- `'none'`: do not correct alignment-axis overflow.

`fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
preferred axis cannot fit:
- `'start'`: allow perpendicular fallback and try the logical start side first
(`top` before `bottom`, or `left` before `right` in LTR).
- `'end'`: allow perpendicular fallback and try the logical end side first
(`bottom` before `top`, or `right` before `left` in LTR).
- `'none'`: do not fallback to the perpendicular axis.

When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
If `align` is omitted, it defaults to `'flip'`. | | `collisionBoundary` | `Boundary` | `clipping-ancestors` | An element or a rectangle that delimits the area that the popup is confined to. | | `collisionPadding` | `Padding` | `5` | Additional space to maintain from the edge of the collision boundary. | | `disableAnchorTracking` | `boolean` | `false` | Whether to disable the popup from tracking any layout shift of its positioning anchor. | | `positionMethod` | `fixed`, `absolute` | `fixed` | Determines which CSS `position` property to use. | | `side` | `bottom`, `left`, `right`, `top`, `inline-end`, `inline-start` | `bottom` | Which side of the anchor element to align the popup against.
May automatically change to avoid collisions. | | `sideOffset` | `number`, `function` | `0` | Distance between the anchor and the popup in pixels.
Also accepts a function that returns the distance to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `sticky` | `boolean` | `false` | Whether to maintain the popup in the viewport after
the anchor element was scrolled out of view. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### FloatingBar.PopupPrimitive | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is opened.
By default, focus moves to the first tabbable element inside the popup, except when the popover
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Form URL: /docs/components/form Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/form/index.mdx Form은 사용자 입력을 수집하고 유효성 검사를 수행하는 폼 컨테이너입니다. ```tsx 'use client'; import { Button, Field, Form, TextInput, VStack } from '@vapor-ui/core'; export default function DefaultForm() { return (
{ event.preventDefault(); const formData = new FormData(event.currentTarget); console.log('Form submitted:', Object.fromEntries(formData)); }} > } $css={{ gap: '$050' }}> Username } $css={{ gap: '$050' }}> Email
); } ```
## Examples *** ### Validation HTML5 기본 유효성 검사를 활용하여 폼 필드를 검증합니다. ```tsx 'use client'; import { Button, Field, Form, TextInput, VStack } from '@vapor-ui/core'; export default function FormValidation() { return (
{ event.preventDefault(); const formData = new FormData(event.currentTarget); console.log('Form submitted:', Object.fromEntries(formData)); }} > } $css={{ gap: '$050' }}> Email Email is required Enter a valid email address } $css={{ gap: '$050' }}> Password Password is required Password must be at least 8 characters
); } ```
### With Field Components 다양한 입력 컴포넌트와 Field를 조합하여 완성된 폼을 구성합니다. ```tsx 'use client'; import { Button, Checkbox, Field, Form, HStack, Select, TextInput, VStack } from '@vapor-ui/core'; export default function FormWithField() { return (
{ event.preventDefault(); const formData = new FormData(event.currentTarget); console.log('Form submitted:', Object.fromEntries(formData)); }} > } $css={{ gap: '$050' }}> Full Name Name is required } $css={{ gap: '$050' }}> Email We'll send a confirmation to this email. Email is required Enter a valid email } $css={{ gap: '$050' }}> Role Developer Designer Manager } $css={{ gap: '$100', alignItems: 'center' }}> I agree to the terms and conditions You must accept the terms
); } ```
## Props Table *** ### Form | Prop | Type | Default | Description | | ---------------- | --------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `validate`: Validates all fields when called. Optionally pass a field name to validate a single field. | | `errors` | `Errors` | - | Validation errors returned externally, typically after submission by a server or a form action.
This should be an object where keys correspond to the `name` attribute on `<Field.Root>`,
and values correspond to error(s) related to that field. | | `onFormSubmit` | `function` | - | Event handler called when the form is submitted.
`preventDefault()` is called on the native submit event when used. | | `validationMode` | `onBlur`, `onChange`, `onSubmit` | `onSubmit` | Determines when the form should be validated.
The `validationMode` prop on `<Field.Root>` takes precedence over this.

- `onSubmit` (default): validates the field when the form is submitted, afterwards fields will re-validate on change.
- `onBlur`: validates a field when it loses focus.
- `onChange`: validates the field on every change to its value. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # IconButton URL: /docs/components/icon-button Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/icon-button/index.mdx IconButton은 특정 작업이나 기능을 나타내며, 텍스트 없이 아이콘만으로 명령을 전달하는 버튼입니다. ```tsx import { IconButton } from '@vapor-ui/core'; import { HeartIcon } from '@vapor-ui/icons'; export default function DefaultIconButton() { return ( ); } ``` ## Property *** ### Size IconButton의 크기를 설정합니다. ```tsx import { HStack, IconButton, Text, VStack } from '@vapor-ui/core'; import { HeartIcon } from '@vapor-ui/icons'; export default function IconButtonSize() { return ( sm md lg xl ); } ``` ### ColorPalette IconButton의 색상을 설정합니다. ```tsx import { HStack, IconButton, Text, VStack } from '@vapor-ui/core'; import { HeartIcon } from '@vapor-ui/icons'; export default function IconButtonColor() { return ( primary secondary success warning danger contrast ); } ``` ### Variant IconButton의 시각적 변형을 설정합니다. ```tsx import { HStack, IconButton, Text, VStack } from '@vapor-ui/core'; import { HeartIcon } from '@vapor-ui/icons'; export default function IconButtonVariant() { return ( fill outline ghost ); } ``` ### Shape IconButton의 모양을 설정합니다. ```tsx import { HStack, IconButton, Text, VStack } from '@vapor-ui/core'; import { HeartIcon } from '@vapor-ui/icons'; export default function IconButtonShape() { return ( square circle ); } ``` ### Disabled IconButton의 비활성화 상태를 설정합니다. ```tsx import { HStack, IconButton, Text, VStack } from '@vapor-ui/core'; import { HeartIcon } from '@vapor-ui/icons'; export default function IconButtonDisabled() { return ( fill outline ghost ); } ``` ## Props Table *** ### IconButton | Prop | Type | Default | Description | | ----------------------- | ------------------------------------------------------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `colorPalette` | `primary`, `secondary`, `success`, `warning`, `danger`, `contrast` | `primary` | Color palette of the button, applied to its background, text, and border according to `variant`. | | `shape` | `circle`, `square` | `square` | Corner style of the icon button. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the button, controlling height, padding, and typography. | | `variant` | `fill`, `outline`, `ghost` | `fill` | Visual style of the button. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `focusableWhenDisabled` | `boolean` | `false` | Whether the button should be focusable when disabled. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # InputGroup URL: /docs/components/input-group Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/input-group/index.mdx InputGroup은 입력 필드(TextInput, Textarea)와 관련 요소들을 그룹화하여 문자 수 카운터와 같은 추가 기능을 제공합니다. ```tsx 'use client'; import { InputGroup, TextInput, VStack } from '@vapor-ui/core'; export default function DefaultInputGroup() { return ( ); } ``` ## Examples *** ### Custom Counter 커스텀 카운터 UI를 구현합니다. ```tsx 'use client'; import { InputGroup, Text, TextInput, VStack } from '@vapor-ui/core'; export default function InputGroupCustomCounter() { return ( 커스텀 카운터 예시 1 {({ count, maxLength }) => `${count} of ${maxLength} characters`} 커스텀 카운터 예시 2 {({ count, maxLength, value }) => ( maxLength * 0.8 ? 'danger-100' : 'hint-100' } > {count}/{maxLength} {value.length > 50 && '(50자 초과)'} )} ); } ``` ## Props Table *** ### InputGroup.Root | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### InputGroup.Counter | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode`, `function` | - | Content shown inside the counter, such as custom count text. As a function, receives `count`, `maxLength`, and `value` of the input and returns the content to display. Replaces the default `count/maxLength` text. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Menu URL: /docs/components/menu Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/menu/index.mdx 드롭다운 Menu와 컨텍스트 Menu를 제공하는 컴포넌트입니다 ```tsx 'use client'; import { Button, Menu } from '@vapor-ui/core'; export default function DefaultMenu() { return ( 메뉴 열기} /> 새 파일 새 폴더 복사 붙여넣기 삭제 ); } ``` ## Property *** ### Disabled Menu의 비활성화 상태를 설정합니다. ```tsx 'use client'; import { Button, HStack, Menu, Text, VStack } from '@vapor-ui/core'; export default function MenuDisabled() { return ( disabled item 일반 메뉴} /> 활성 아이템 1 비활성 아이템 활성 아이템 2 비활성 아이템 2 활성 아이템 3 disabled menu 비활성 메뉴} /> 아이템 1 아이템 2 아이템 3 ); } ``` ## Examples *** ### Positioning Menu의 표시 위치를 설정합니다. ```tsx 'use client'; import { Button, HStack, Menu, Text, VStack } from '@vapor-ui/core'; export default function MenuPositioning() { return ( top 상단 메뉴} /> 상단 아이템 1 상단 아이템 2 상단 아이템 3 right 우측 메뉴} /> 우측 아이템 1 우측 아이템 2 우측 아이템 3 bottom 하단 메뉴} /> 하단 아이템 1 하단 아이템 2 하단 아이템 3 left 좌측 메뉴} /> 좌측 아이템 1 좌측 아이템 2 좌측 아이템 3 ); } ``` ### Groups Menu 아이템을 그룹화합니다. ```tsx 'use client'; import { Button, Menu } from '@vapor-ui/core'; export default function MenuGroups() { return ( 그룹 메뉴} /> 파일 새 파일 파일 열기 파일 저장 편집 복사 붙여넣기 잘라내기 도구 설정 도움말 ); } ``` ### With Checkbox Items Checkbox Item을 사용합니다. ```tsx 'use client'; import { useState } from 'react'; import { Button, Menu } from '@vapor-ui/core'; export default function MenuCheckbox() { const [showToolbar, setShowToolbar] = useState(true); const [showSidebar, setShowSidebar] = useState(false); const [showStatusbar, setShowStatusbar] = useState(true); return ( 보기 설정} /> 보기 옵션 툴바 표시 사이드바 표시 상태바 표시 ); } ``` ### With Radio Items Radio Item을 사용합니다. ```tsx 'use client'; import { useState } from 'react'; import { Button, Menu } from '@vapor-ui/core'; export default function MenuRadio() { const [fontSize, setFontSize] = useState('medium'); return ( 글꼴 크기} /> 글꼴 크기 선택 작게 (12px) 보통 (14px) 크게 (16px) 매우 크게 (18px) ); } ``` ### With Submenu Submenu를 구성할 수 있습니다. ```tsx 'use client'; import { Button, Menu } from '@vapor-ui/core'; export default function MenuSubmenu() { return ( 서브메뉴} /> 새 파일 파일 열기 최근 파일 document.txt presentation.pptx spreadsheet.xlsx 더 많은 파일... 내보내기 PDF로 내보내기 이미지로 내보내기 HTML로 내보내기 종료 ); } ``` ## Props Table *** ### Menu.Root | Prop | Type | Default | Description | | ---------------------- | -------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `defaultOpen` | `boolean` | `false` | Whether the menu is initially open.

To render a controlled menu, use the `open` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the menu is opened or closed. | | `open` | `boolean` | - | Whether the menu is currently open. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the menu.
Call this after any externally controlled closing animation finishes.
- `close`: When specified, the menu can be closed imperatively. | | `children` | `ReactNode`, `function` | - | The content of the menu.
This can be a regular React node or a render function that receives the `payload` of the active trigger. | | `closeParentOnEsc` | `boolean` | `false` | When in a submenu, determines whether pressing the Escape key
closes the entire menu, or only the current child menu. | | `defaultTriggerId` | `string`, `null` | - | ID of the trigger that the menu is associated with.
This is useful in conjunction with the `defaultOpen` prop to create an initially open menu. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `handle` | `MenuHandle` | - | A handle to associate the menu with a trigger.
If specified, allows external triggers to control the menu's open state. | | `highlightItemOnHover` | `boolean` | `true` | Whether moving the pointer over items should highlight them.
Disabling this prop allows CSS `:hover` to be differentiated from the `:focus` (`data-highlighted`) state. | | `loopFocus` | `boolean` | `true` | Whether to loop keyboard focus back to the first item
when the end of the list is reached while using the arrow keys. | | `modal` | `boolean` | `true` | Determines if the menu enters a modal state when open.
- `true`: user interaction is limited to the menu: document page scroll is locked and pointer interactions on outside elements are disabled.
- `false`: user interaction with the rest of the document is allowed.

On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior.

Nested menus ignore this prop, and menus opened by hover are never modal. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the menu is opened or closed. | | `orientation` | `horizontal`, `vertical` | `vertical` | The visual orientation of the menu.
Controls whether roving focus uses up/down or left/right arrow keys. | | `triggerId` | `string`, `null` | - | ID of the trigger that the menu is associated with.
This is useful in conjunction with the `open` prop to create a controlled menu.
There's no need to specify this prop when the menu is uncontrolled (that is, when the `open` prop is not set). | ### Menu.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Content shown inside the trigger, such as a label or an icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeDelay` | `number` | `0` | How long to wait before closing the menu that was opened on hover.
Specified in milliseconds.

Requires the `openOnHover` prop. | | `delay` | `number` | `100` | How long to wait before the menu may be opened on hover. Specified in milliseconds.

Requires the `openOnHover` prop. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `handle` | `MenuHandle` | - | A handle to associate the trigger with a menu. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `openOnHover` | `boolean` | - | Whether the menu should also open when the trigger is hovered. | | `payload` | `unknown` | - | A payload to pass to the menu when it is opened. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.PositionerPrimitive | Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Menu items shown in the panel, such as `Menu.Item`, `Menu.Group`, or `Menu.Separator`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `portalElement` | `ReactElement` | - | Replaces the default `Menu.PortalPrimitive`. Use to change the portal container. | | `positionerElement` | `ReactElement` | - | Replaces the default `Menu.PositionerPrimitive`. Use to change the side, alignment, or offset of the popup. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the menu is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.PortalPrimitive | Prop | Type | Default | Description | | ------------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `keepMounted` | `boolean` | `false` | Whether to keep the portal mounted in the DOM while the popup is hidden. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.PositionerPrimitive | Prop | Type | Default | Description | | ----------------------- | ----------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `align` | `center`, `end`, `start` | `start` | How to align the popup relative to the specified side.

Submenus and menubars default to `'start'`. | | `alignOffset` | `number`, `function` | `0` | Additional offset along the alignment axis in pixels.
Also accepts a function that returns the offset to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `anchor` | `Element`, `VirtualElement`, `React.RefObject`, `function`, `null` | - | An element to position the popup against.
By default, the popup will be positioned against the trigger. | | `arrowPadding` | `number` | `5` | Minimum distance to maintain between the arrow and the edges of the popup.

Use it to prevent the arrow element from hanging out of the rounded corners of a popup. | | `collisionAvoidance` | `CollisionAvoidance` | - | Determines how to handle collisions when positioning the popup.

`side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):
- `'flip'`: keep the requested side when it fits; otherwise try the opposite side
(`top` and `bottom`, or `left` and `right`).
- `'shift'`: never change side; keep the requested side and move the popup within
the clipping boundary so it stays visible.
- `'none'`: do not correct side-axis overflow.

`align` controls overflow on the alignment axis (`start`/`center`/`end`):
- `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
- `'shift'`: keep side and requested alignment, then nudge the popup along the
alignment axis to fit.
- `'none'`: do not correct alignment-axis overflow.

`fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
preferred axis cannot fit:
- `'start'`: allow perpendicular fallback and try the logical start side first
(`top` before `bottom`, or `left` before `right` in LTR).
- `'end'`: allow perpendicular fallback and try the logical end side first
(`bottom` before `top`, or `right` before `left` in LTR).
- `'none'`: do not fallback to the perpendicular axis.

When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
If `align` is omitted, it defaults to `'flip'`. | | `collisionBoundary` | `Boundary` | `clipping-ancestors` | An element or a rectangle that delimits the area that the popup is confined to. | | `collisionPadding` | `Padding` | `5` | Additional space to maintain from the edge of the collision boundary. | | `disableAnchorTracking` | `boolean` | `false` | Whether to disable the popup from tracking any layout shift of its positioning anchor. | | `positionMethod` | `fixed`, `absolute` | `absolute` | Determines which CSS `position` property to use. | | `side` | `bottom`, `left`, `right`, `top`, `inline-end`, `inline-start` | `bottom` | Which side of the anchor element to align the popup against.
May automatically change to avoid collisions.

Submenus and vertical menubars default to `'inline-end'`. | | `sideOffset` | `number`, `function` | `4` | Distance between the anchor and the popup in pixels.
Also accepts a function that returns the distance to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `sticky` | `boolean` | `false` | Whether to maintain the popup in the viewport after
the anchor element was scrolled out of view. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.PopupPrimitive | Prop | Type | Default | Description | | ------------ | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Menu items shown in the panel, such as `Menu.Item`, `Menu.Group`, or `Menu.Separator`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the menu is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.CheckboxItemIndicatorPrimitive | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeOnClick` | `boolean` | `true` | Whether to close the menu when the item is clicked. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `onClick` | `function` | - | The click handler for the menu item. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.RadioItemIndicatorPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `orientation` | `horizontal`, `vertical` | `horizontal` | The orientation of the separator. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.Group | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `children` | `ReactNode` | - | The content of the component. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.GroupLabel | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.SubmenuRoot | Prop | Type | Default | Description | | ---------------------- | -------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultOpen` | `boolean` | `false` | Whether the menu is initially open.

To render a controlled menu, use the `open` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the menu is opened or closed. | | `open` | `boolean` | - | Whether the menu is currently open. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the menu.
Call this after any externally controlled closing animation finishes.
- `close`: When specified, the menu can be closed imperatively. | | `children` | `ReactNode` | - | The content of the submenu. | | `closeParentOnEsc` | `boolean` | `false` | When in a submenu, determines whether pressing the Escape key
closes the entire menu, or only the current child menu. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `highlightItemOnHover` | `boolean` | `true` | Whether moving the pointer over items should highlight them.
Disabling this prop allows CSS `:hover` to be differentiated from the `:focus` (`data-highlighted`) state. | | `loopFocus` | `boolean` | `true` | Whether to loop keyboard focus back to the first item
when the end of the list is reached while using the arrow keys. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the menu is opened or closed. | | `orientation` | `horizontal`, `vertical` | `vertical` | The visual orientation of the menu.
Controls whether roving focus uses up/down or left/right arrow keys. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.SubmenuTriggerItem | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `onClick` | `function` | - | Called when the item is clicked. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeDelay` | `number` | `0` | How long to wait before closing the menu that was opened on hover.
Specified in milliseconds.

Requires the `openOnHover` prop. | | `delay` | `number` | `100` | How long to wait before the menu may be opened on hover. Specified in milliseconds.

Requires the `openOnHover` prop. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `openOnHover` | `boolean` | `true` | Whether the menu should also open when the trigger is hovered. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.SubmenuPopup | Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Nested menu items shown in the submenu panel, such as `Menu.Item` or `Menu.CheckboxItem`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `portalElement` | `ReactElement` | - | Replaces the default `Menu.PortalPrimitive`. Use to change the portal container. | | `positionerElement` | `ReactElement` | - | Replaces the default `Menu.PositionerPrimitive`. Use to change the side, alignment, or offset of the popup. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the menu is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.SubmenuPopupPrimitive | Prop | Type | Default | Description | | ------------ | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Nested menu items shown in the submenu panel, such as `Menu.Item` or `Menu.CheckboxItem`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the menu is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.CheckboxItem | Prop | Type | Default | Description | | ----------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `checked` | `boolean` | - | Whether the checkbox item is currently ticked.

To render an uncontrolled checkbox item, use the `defaultChecked` prop instead. | | `defaultChecked` | `boolean` | `false` | Whether the checkbox item is initially ticked.

To render a controlled checkbox item, use the `checked` prop instead. | | `onCheckedChange` | `function` | - | Event handler called when the checkbox item is ticked or unticked. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeOnClick` | `boolean` | `false` | Whether to close the menu when the item is clicked. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `onClick` | `function` | - | The click handler for the menu item. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.CheckboxItemPrimitive | Prop | Type | Default | Description | | ----------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `checked` | `boolean` | - | Whether the checkbox item is currently ticked.

To render an uncontrolled checkbox item, use the `defaultChecked` prop instead. | | `defaultChecked` | `boolean` | `false` | Whether the checkbox item is initially ticked.

To render a controlled checkbox item, use the `checked` prop instead. | | `onCheckedChange` | `function` | - | Event handler called when the checkbox item is ticked or unticked. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeOnClick` | `boolean` | `false` | Whether to close the menu when the item is clicked. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `onClick` | `function` | - | The click handler for the menu item. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.CheckboxItemIndicatorPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | `true` | Whether to keep the HTML element in the DOM when the checkbox item is not checked. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.RadioGroup | Prop | Type | Default | Description | | --------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultValue` | `any` | - | The uncontrolled value of the radio item that should be initially selected.

To render a controlled radio group, use the `value` prop instead. | | `onValueChange` | `function` | - | Function called when the selected value changes. | | `value` | `any` | - | The controlled value of the radio item that should be currently selected.

To render an uncontrolled radio group, use the `defaultValue` prop instead. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `children` | `ReactNode` | - | The content of the component. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Menu.RadioItem | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `any` | - | Value of the radio item.
This is the value that will be set in the MenuRadioGroup when the item is selected. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeOnClick` | `boolean` | `false` | Whether to close the menu when the item is clicked. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `onClick` | `function` | - | The click handler for the menu item. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.RadioItemPrimitive | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `any` | - | Value of the radio item.
This is the value that will be set in the MenuRadioGroup when the item is selected. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeOnClick` | `boolean` | `false` | Whether to close the menu when the item is clicked. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `onClick` | `function` | - | The click handler for the menu item. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Menu.RadioItemIndicatorPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | `false` | Whether to keep the HTML element in the DOM when the radio item is inactive. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Meter URL: /docs/components/meter Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/meter/index.mdx Meter는 디스크 사용량이나 점수처럼 알려진 범위 안의 측정값을 표시합니다. ```tsx import { Meter } from '@vapor-ui/core'; export default function DefaultMeter() { return ( 저장 공간 ); } ``` `Meter.Label`과 `Meter.Value`는 한 줄에 놓이고 `Meter.Track`이 그 아래 전체 폭을 차지합니다. 이 배치는 자식 순서를 따르므로 `Meter.Value`는 `Meter.Track` 앞에 두세요. 뒤에 두면 값이 트랙 아래로 내려갑니다. `Meter.Label`은 보조기술에 전달되는 이름이기도 합니다. `저장 공간`, `CPU 사용률`처럼 **무엇을 재는 값인지**를 문구에 담으세요. 화면에 이름을 두지 않을 때는 `Meter.Label` 대신 `Meter.Root`에 `aria-label`을 주세요 — 둘을 함께 주면 `aria-label`이 무시됩니다. ## Property *** ### Size `size`로 트랙의 높이를 조절합니다. ```tsx import { Meter, VStack } from '@vapor-ui/core'; export default function MeterSize() { return ( {(['sm', 'md', 'lg'] as const).map((size) => ( 저장 공간 ({size}) ))} ); } ``` ### Type `type`으로 채워진 영역의 색상을 지정합니다. 색만으로는 위험 구간을 알 수 없으므로 레이블에도 함께 적어줍니다. ```tsx import { Meter, VStack } from '@vapor-ui/core'; export default function MeterType() { return ( 저장 공간 저장 공간 부족 ); } ``` ### Range `min`, `max`로 범위를, `format`으로 표시 형식을 지정합니다. 값 텍스트가 단위만 담고 있다면 `getAriaValueText`로 무엇을 재는 값인지 함께 읽히도록 합니다. ```tsx import { Meter } from '@vapor-ui/core'; export default function MeterRange() { return ( `8GB 중 ${formattedValue} 사용`} $css={{ maxWidth: '20rem' }} > 저장 공간 ); } ``` ## Examples *** ### Auto Update 값이 스스로 바뀌는 미터에는 갱신을 멈출 수단을 함께 둡니다. 갱신 간격은 초당 3회를 넘기지 않습니다. ```tsx import { useEffect, useState } from 'react'; import { Button, Meter, VStack } from '@vapor-ui/core'; export default function MeterAutoUpdate() { const [value, setValue] = useState(42); const [running, setRunning] = useState(true); useEffect(() => { if (!running) return; const id = setInterval(() => setValue((prev) => (prev + 7) % 101), 1000); return () => clearInterval(id); }, [running]); return ( CPU 사용률 ); } ``` ## Accessibility *** `role="meter"`와 `aria-valuenow` / `aria-valuemin` / `aria-valuemax`는 `Meter`가 알아서 붙입니다. 나머지는 컴포넌트가 대신 지킬 수 없으니 **쓰는 쪽에서 챙겨야 합니다.** ### 진행률에는 쓰지 마세요 `Meter`가 다루는 값은 **범위가 정해진 지금의 측정값**입니다. 디스크 사용량, 점수, 잔량이 여기 해당합니다. 작업이 얼마나 끝났는지 보여주는 진행률이나 상한이 없는 값은 대상이 아닙니다. 진행률에 `role="meter"`가 붙으면 보조기술은 "완료를 향해 가는 값"이 아니라 "지금 재고 있는 값"으로 읽습니다. `render`로 역할만 갈아끼우지 말고 진행률에 맞는 컴포넌트를 쓰세요. ### 이름은 하나만 주세요 `Meter.Label`을 렌더하면 `Meter.Root`에 준 `aria-label`은 이름 계산에서 밀려납니다. 오류도 경고도 없이 조용히 사라지니 둘 중 하나만 쓰세요. * 이름을 화면에 보여준다 → `Meter.Label` * 화면에 이름을 두지 않는다 → `Meter.Root`의 `aria-label` ### 같은 값은 같은 문구·같은 형식으로 한 측정값이 여러 화면에 나온다면 레이블 문구와 `format`을 맞추세요. 여기서는 `저장 공간 4.2GB`, 저기서는 `디스크 52%`라면 읽는 사람은 둘이 같은 값인지 알 길이 없습니다. ### 자동으로 갱신된다면 멈출 수단을 두세요 값이 5초를 넘겨 저절로 바뀐다면 사용자가 일시정지·정지·숨김 중 하나를 고를 수 있어야 합니다. 갱신 간격은 **초당 3회 이하**로 잡으세요. 그보다 빠르면 화면이 깜빡이는 것처럼 보입니다. 위 [Auto Update](#auto-update)가 그 예입니다. ### 색을 바꿀 때는 대비를 확인하세요 `className`이나 `$css`로 색을 갈아끼우면 기본 색이 맞춰 둔 대비가 무너집니다. * `Meter.Label` / `Meter.Value` 텍스트 대 배경 — **4.5:1** 이상 * `Meter.IndicatorPrimitive` 대 `Meter.Track`, `Meter.Track` 대 페이지 배경 — **3:1** 이상 `type="warning"`처럼 색으로 상태를 알린다면 그 상태를 레이블 문구에도 적으세요. 색을 구분하지 못하는 사용자에게는 문구가 유일한 단서입니다. ### 미터를 가리킬 때 모양·색·위치로만 말하지 마세요 "오른쪽 초록 막대를 확인하세요" 같은 안내는 그 색과 위치를 알아채는 사람에게만 통합니다. 미터를 가리킬 때는 레이블 문구를 부르세요. ### 페이지와 언어가 다르면 표시하세요 레이블이 페이지 언어와 다른 언어로 적혀 있다면 그 요소에 `lang`을 주세요. 값 형식도 그 언어를 따라야 한다면 `locale`까지 맞춥니다. ### 폭을 고정하지 마세요 `Meter.Root`는 기본이 `width: 100%`입니다. `width`를 고정하는 대신 `max-width`를 쓰면 320px 폭에서도, 200% 확대에서도 내용이 잘리지 않습니다. ### 값은 텍스트로 보여주세요 `42%` 같은 숫자를 그림으로 만들어 넣지 마세요. `Meter.Value`가 내는 텍스트여야 사용자가 글자 크기나 자간을 바꿨을 때 값도 함께 바뀝니다. ## Props Table *** ### Meter.Root | Prop | Type | Default | Description | | ------------------ | --------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `number` | - | The current value. | | `size` | `sm`, `md`, `lg` | `md` | Size of the meter, controlling the height of the track. | | `type` | `default`, `warning` | `default` | Color of the filled portion of the meter. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `aria-valuetext` | `string` | - | A string value that provides a user-friendly name for `aria-valuenow`, the current value of the meter. | | `format` | `Intl.NumberFormatOptions` | - | Options to format the value. | | `getAriaValueText` | `function` | - | A function that returns a string value that provides a human-readable text alternative for `aria-valuenow`, the current value of the meter. | | `locale` | `Intl.LocalesArgument` | - | The locale used by `Intl.NumberFormat` when formatting the value.
Defaults to the user's runtime locale. | | `max` | `number` | `100` | The maximum value | | `min` | `number` | `0` | The minimum value | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Meter.Label | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Meter.Value | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `function`, `null` | - | Content shown inside the value. As a function, receives the formatted value and the raw number and returns what to display. Shows the formatted value when omitted. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Meter.Track | Prop | Type | Default | Description | | ------------------ | --------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `indicatorElement` | `ReactElement` | - | Replaces the default `Meter.IndicatorPrimitive`. Use to change the filled portion of the track. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Meter.TrackPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Meter.IndicatorPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # MultiSelect URL: /docs/components/multi-select Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/multi-select/index.mdx MultiSelect는 사용자가 여러 옵션 중에서 다중 선택할 수 있는 드롭다운 컴포넌트입니다. 선택된 값들은 배지 형태로 표시되며, 태그 선택, 필터링, 카테고리 선택 등에 사용됩니다. ```tsx import { MultiSelect } from '@vapor-ui/core'; const fonts = [ { label: 'Sans-serif', value: 'sans' }, { label: 'Serif', value: 'serif' }, { label: 'Monospace', value: 'mono' }, { label: 'Cursive', value: 'cursive' }, ]; export default function DefaultMultiSelect() { return ( {fonts.map((font) => ( {font.label} ))} ); } ``` ## Property *** ### Size MultiSelect의 크기를 설정합니다. ```tsx import { HStack, MultiSelect, Text, VStack } from '@vapor-ui/core'; const options = [ { label: '옵션 1', value: 'option1' }, { label: '옵션 2', value: 'option2' }, { label: '옵션 3', value: 'option3' }, ]; export default function MultiSelectSize() { return ( sm md lg xl ); } const MultiSelectTemplate = (props: MultiSelect.Root.Props) => { return ( {options.map((option) => ( {option.label} ))} ); }; ``` ### Controlled State MultiSelect의 선택 상태를 제어합니다. ```tsx 'use client'; import { useState } from 'react'; import { Button, HStack, MultiSelect, Text, VStack } from '@vapor-ui/core'; const fonts = [ { label: 'Sans-serif', value: 'sans' }, { label: 'Serif', value: 'serif' }, { label: 'Monospace', value: 'mono' }, { label: 'Cursive', value: 'cursive' }, ]; export default function MultiSelectControlled() { const [value, setValue] = useState([]); const handleValueChange = (newValue: unknown) => { setValue(newValue as string[]); }; return ( {fonts.map((font) => ( {font.label} ))} 선택된 값:{' '} {value.length > 0 ? value.join(', ') : '없음'} ); } ``` ### States MultiSelect의 다양한 상태를 설정합니다. ```tsx import { HStack, MultiSelect, Text, VStack } from '@vapor-ui/core'; const options = [ { label: '옵션 1', value: 'option1' }, { label: '옵션 2', value: 'option2' }, { label: '옵션 3', value: 'option3' }, ]; export default function MultiSelectStates() { return ( default disabled readOnly invalid ); } export const MultiSelectTemplate = (props: MultiSelect.Root.Props) => { return ( {options.map((option) => ( {option.label} ))} ); }; ``` ## Examples *** ### Items Configuration 다양한 형태의 아이템 데이터를 사용합니다. ```tsx import { MultiSelect, Text, VStack } from '@vapor-ui/core'; const fonts = [ { label: 'Sans-serif', value: 'sans' }, { label: 'Serif', value: 'serif' }, { label: 'Monospace', value: 'mono' }, { label: 'Cursive', value: 'cursive' }, ]; const languages = { javascript: 'JavaScript', typescript: 'TypeScript', python: 'Python', java: 'Java', go: 'Go', }; export default function MultiSelectItems() { return ( 배열 형태의 아이템 {fonts.map((font) => ( {font.label} ))} 객체 형태의 아이템 {Object.entries(languages).map(([value, label]) => ( {label} ))} ); } ``` ### Grouping Options 옵션을 그룹으로 묶어 구조화합니다. ```tsx import { Box, MultiSelect } from '@vapor-ui/core'; export default function MultiSelectGrouping() { return ( } $css={{ width: '400px' }} /> 프론트엔드 React Vue Angular Svelte 백엔드 Node.js Python Java Go 데이터베이스 MySQL PostgreSQL MongoDB Redis ); } ``` ### Custom Value Display MultiSelect.Value에 함수형 children을 제공하여 선택된 값들의 표시 방법을 커스터마이징할 수 있습니다. 기본적으로는 배지 형태로 표시되지만, 문자열이나 커스텀 컴포넌트로 변경할 수 있습니다. ```tsx import { Badge, Flex, HStack, MultiSelect, Text, VStack } from '@vapor-ui/core'; const languages = { javascript: 'JavaScript', typescript: 'TypeScript', python: 'Python', java: 'Java', go: 'Go', rust: 'Rust', }; const renderRestValue = (value: string[]) => { if (!value.length) { return '언어 선택'; } const displayValues = value.slice(0, 2); const remainingCount = value.length - 2; return ( {displayValues.map((val) => ( {languages[val as keyof typeof languages]} ))} {remainingCount > 0 && ( +{remainingCount} more )} ); }; const renderStringValue = (value: string[]) => { if (!value.length) { return '언어 선택'; } return value.map((v) => languages[v as keyof typeof languages]).join(', '); }; export default function MultiSelectCustomValue() { return ( 커스텀 값 표시 (최대 2개 + 더보기) {renderRestValue} {Object.entries(languages).map(([value, label]) => ( {label} ))} 문자열 형태 표시 {renderStringValue} {Object.entries(languages).map(([value, label]) => ( {label} ))} ); } ``` ## Props Table *** ### MultiSelect.Root | Prop | Type | Default | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid` | `boolean` | `false` | Marks the multi-select as invalid, applying error styles. Sets `aria-invalid` on the trigger `<button>` element. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the multi-select, controlling minimum height, padding, typography, and the size of its icon and badges. | | `defaultOpen` | `boolean` | `false` | Whether the select popup is initially open.

To render a controlled select popup, use the `open` prop instead. | | `defaultValue` | `Value[]`, `null` | - | The uncontrolled value of the select when it's initially rendered.

To render a controlled select, use the `value` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the select popup is opened or closed. | | `onValueChange` | `function` | - | Event handler called when the value of the select changes. | | `open` | `boolean` | - | Whether the select popup is currently open. | | `value` | `Value[]`, `null` | - | The value of the select. Use when controlled. | | `children` | `ReactNode` | - | Parts of the multi-select, such as `MultiSelect.Trigger` and `MultiSelect.Popup`. | | `placeholder` | `ReactNode` | - | Text shown in the trigger when no value is selected. The `children` of `MultiSelect.ValuePrimitive`, or the label of an item whose value is `null` in `items`, takes precedence over it. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the select.
Call this after any externally controlled closing animation finishes. | | `autoComplete` | `string` | - | Provides a hint to the browser for autofill. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `form` | `string` | - | Identifies the form that owns the hidden input.
Useful when the select is rendered outside the form. | | `highlightItemOnHover` | `boolean` | `true` | Whether moving the pointer over items should highlight them.
Disabling this prop allows CSS `:hover` to be differentiated from the `:focus` (`data-highlighted`) state. | | `id` | `string` | - | The id of the Select. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `isItemEqualToValue` | `function` | - | Custom comparison logic used to determine if a select item value matches the current selected value. Useful when item values are objects without matching referentially.
Defaults to `Object.is` comparison. | | `items` | `Record`, `readonly { label: React.ReactNode; value: any; }[]`, `readonly Group[]` | - | Data structure of the items rendered in the select popup.
When specified, `<Select.Value>` renders the label of the selected item instead of the raw value. | | `itemToStringLabel` | `function` | - | When the item values are objects (`<Select.Item value={object}>`), this function converts the object value to a string representation for display in the trigger.
If the shape of the object is `{ value, label }`, the label will be used automatically without needing to specify this prop. | | `itemToStringValue` | `function` | - | When the item values are objects (`<Select.Item value={object}>`), this function converts the object value to a string representation for form submission.
If the shape of the object is `{ value, label }`, the value will be used automatically without needing to specify this prop. | | `modal` | `boolean` | `true` | Determines if the select enters a modal state when open.
- `true`: user interaction is limited to the select: document page scroll is locked and pointer interactions on outside elements are disabled.
- `false`: user interaction with the rest of the document is allowed.

On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior. | | `name` | `string` | - | Identifies the field when a form is submitted. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the select popup is opened or closed. | | `readOnly` | `boolean` | `false` | Whether the user should be unable to choose a different option from the select popup. | | `required` | `boolean` | `false` | Whether the user must choose a value before submitting a form. | ### MultiSelect.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Not rendered: the trigger always shows the selected values and a chevron icon. Use `MultiSelect.TriggerPrimitive` to compose custom content. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.TriggerPrimitive | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Content shown inside the trigger, such as `MultiSelect.ValuePrimitive` and `MultiSelect.TriggerIconPrimitive`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | `<button />` | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.TriggerIconPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown in place of the default chevron icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.ValuePrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `children` | `ReactNode`, `function` | - | Accepts a function that returns a `ReactNode` to format the selected value.
Treat the value as read-only: in `multiple` mode it may be a shared frozen array
when nothing is selected. | | `placeholder` | `ReactNode` | - | The placeholder value to display when no value is selected.
This is overridden by `children` if specified, or by a null item's label in `items`. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.PlaceholderPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### MultiSelect.Popup | Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `children` | `ReactNode` | - | Options shown in the popup, such as `MultiSelect.Item`, `MultiSelect.Group`, or `MultiSelect.Separator`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `portalElement` | `ReactElement` | - | Replaces the default `MultiSelect.PortalPrimitive`. Use to change the portal container. | | `positionerElement` | `ReactElement` | - | Replaces the default `MultiSelect.PositionerPrimitive`. Use to change the side, alignment, or offset of the popup. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the select popup is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.PortalPrimitive | Prop | Type | Default | Description | | ----------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.PositionerPrimitive | Prop | Type | Default | Description | | ----------------------- | ----------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `align` | `center`, `end`, `start` | `start` | How to align the popup relative to the specified side. | | `alignItemWithTrigger` | `boolean` | `false` | Whether the positioner overlaps the trigger so the selected item's text is aligned with the trigger's value text. This only applies to mouse input and is automatically disabled if there is not enough space. | | `alignOffset` | `number`, `function` | `0` | Additional offset along the alignment axis in pixels.
Also accepts a function that returns the offset to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `anchor` | `Element`, `VirtualElement`, `React.RefObject`, `function`, `null` | - | An element to position the popup against.
By default, the popup will be positioned against the trigger. | | `arrowPadding` | `number` | `5` | Minimum distance to maintain between the arrow and the edges of the popup.

Use it to prevent the arrow element from hanging out of the rounded corners of a popup. | | `collisionAvoidance` | `CollisionAvoidance` | - | Determines how to handle collisions when positioning the popup.

`side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):
- `'flip'`: keep the requested side when it fits; otherwise try the opposite side
(`top` and `bottom`, or `left` and `right`).
- `'shift'`: never change side; keep the requested side and move the popup within
the clipping boundary so it stays visible.
- `'none'`: do not correct side-axis overflow.

`align` controls overflow on the alignment axis (`start`/`center`/`end`):
- `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
- `'shift'`: keep side and requested alignment, then nudge the popup along the
alignment axis to fit.
- `'none'`: do not correct alignment-axis overflow.

`fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
preferred axis cannot fit:
- `'start'`: allow perpendicular fallback and try the logical start side first
(`top` before `bottom`, or `left` before `right` in LTR).
- `'end'`: allow perpendicular fallback and try the logical end side first
(`bottom` before `top`, or `right` before `left` in LTR).
- `'none'`: do not fallback to the perpendicular axis.

When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
If `align` is omitted, it defaults to `'flip'`. | | `collisionBoundary` | `Boundary` | `clipping-ancestors` | An element or a rectangle that delimits the area that the popup is confined to. | | `collisionPadding` | `Padding` | `5` | Additional space to maintain from the edge of the collision boundary. | | `disableAnchorTracking` | `boolean` | `false` | Whether to disable the popup from tracking any layout shift of its positioning anchor. | | `positionMethod` | `fixed`, `absolute` | `absolute` | Determines which CSS `position` property to use. | | `side` | `bottom`, `left`, `right`, `top`, `inline-end`, `inline-start` | `bottom` | Which side of the anchor element to align the popup against.
May automatically change to avoid collisions. | | `sideOffset` | `number`, `function` | `4` | Distance between the anchor and the popup in pixels.
Also accepts a function that returns the distance to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `sticky` | `boolean` | `false` | Whether to maintain the popup in the viewport after
the anchor element was scrolled out of view. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.PopupPrimitive | Prop | Type | Default | Description | | ------------ | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `children` | `ReactNode` | - | Options shown in the popup, such as `MultiSelect.Item`, `MultiSelect.Group`, or `MultiSelect.Separator`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the select popup is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### MultiSelect.Item | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` | `any` | `null` | A unique value that identifies this select item. | | `children` | `ReactNode` | - | Label of the option, such as its text or an icon with text. The check mark is added after it. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Specifies the text label to use when the item is matched during keyboard text navigation.

Defaults to the item text content if not provided. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.ItemPrimitive | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` | `any` | `null` | A unique value that identifies this select item. | | `children` | `ReactNode` | - | Content shown inside the option, such as its label and `MultiSelect.ItemIndicatorPrimitive`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Specifies the text label to use when the item is matched during keyboard text navigation.

Defaults to the item text content if not provided. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### MultiSelect.ItemIndicatorPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown in place of the default check icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | - | Whether to keep the HTML element in the DOM when the item is not selected. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### MultiSelect.Separator | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `orientation` | `horizontal`, `vertical` | `horizontal` | The orientation of the separator. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### MultiSelect.Group | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### MultiSelect.GroupLabel | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # NavigationMenu URL: /docs/components/navigation-menu Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/navigation-menu/index.mdx 여러 콘텐츠 섹션 간에 전환할 수 있도록 돕는 요소로 클릭 시 페이지가 이동합니다. ```tsx import { NavigationMenu } from '@vapor-ui/core'; export default function DefaultNavigationMenu() { return ( Default Link Current Link Disabled Link ); } ``` ## Property *** ### Size NavigationMenu의 크기를 설정합니다. ```tsx import { HStack, NavigationMenu, Text, VStack } from '@vapor-ui/core'; export default function NavigationMenuSize() { return ( sm Home About md Home About lg Home About xl Home About ); } ``` ### Direction NavigationMenu의 방향을 설정합니다. ```tsx import { HStack, NavigationMenu, Text, VStack } from '@vapor-ui/core'; export default function NavigationMenuDirection() { return ( horizontal Home About Contact vertical Home About Contact ); } ``` ### Disabled NavigationMenu의 비활성화 상태를 설정합니다. ```tsx import { NavigationMenu } from '@vapor-ui/core'; export default function NavigationMenuDisabled() { return (

기본 상태와 비활성화 상태

활성 링크 비활성화 링크 다른 활성 링크

현재 페이지와 비활성화 상태

홈 현재 페이지 비활성화 링크 연락처
); } ```
### Current NavigationMenu의 현재 페이지 상태를 설정합니다. ```tsx import { NavigationMenu } from '@vapor-ui/core'; export default function NavigationMenuCurrent() { return (

현재 페이지 표시

홈 제품 (현재 페이지) 서비스 회사소개
); } ```
## Examples *** ### With Icons 아이콘과 함께 사용합니다. ```tsx import { NavigationMenu } from '@vapor-ui/core'; import { HomeIcon, SettingIcon, StarIcon, UserIcon } from '@vapor-ui/icons'; export default function NavigationMenuWithIcon() { return (

아이콘과 텍스트 조합

홈 즐겨찾기 프로필 설정

아이콘만 사용

세로 방향에서의 아이콘

대시보드 즐겨찾기 사용자 관리 시스템 설정
); } ```
### With Popup 팝오버 형태로 사용합니다. ```tsx import { NavigationMenu, VStack } from '@vapor-ui/core'; export default function NavigationMenuSelected() { return (

선택된 상태 표시

아이템 1 내용물 1 아이템 2 내용물 2 아이템 3 내용물 3
); } ```
### Flexible Usage NavigationMenu의 모든 프리셋 컴포넌트를 분리하여 사용합니다. ```tsx import { NavigationMenu } from '@vapor-ui/core'; export default function NavigationMenuSelected() { return (
홈 아이템 내용물
); } ```
## Props Table *** ### NavigationMenu.Root | Prop | Type | Default | Description | | ---------------------- | ------------------------------------------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `direction` | `horizontal`, `vertical` | `horizontal` | Layout direction of the menu items, which also sets the arrow keys that move focus between them. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the links and triggers, controlling height, padding, and typography. | | `defaultValue` | `unknown` | `null` | The uncontrolled value of the item that should be initially selected.

To render a controlled navigation menu, use the `value` prop instead. | | `onValueChange` | `function` | - | Callback fired when the value changes. | | `value` | `unknown` | `null` | The controlled value of the navigation menu item that should be currently open.
When non-nullish, the menu will be open. When nullish, the menu will be closed.

To render an uncontrolled navigation menu, use the `defaultValue` prop instead. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `disabled` | `boolean` | - | Disables every link and trigger in the menu, blocking all interactions. A `disabled` set on a link or trigger takes precedence. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions. | | `closeDelay` | `number` | `50` | How long to wait before closing the navigation popup. Specified in milliseconds. | | `delay` | `number` | `50` | How long to wait before opening the navigation popup. Specified in milliseconds. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the navigation menu is closed. | | `orientation` | `horizontal`, `vertical` | - | The orientation of the navigation menu. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### NavigationMenu.List | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### NavigationMenu.Item | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` | `any` | - | A unique value that identifies this navigation menu item.
If no value is provided, a unique ID will be generated automatically.
Use when controlling the navigation menu programmatically. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### NavigationMenu.Link | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `current` | `boolean` | - | Marks the link as the current page, applying the active style and setting `aria-current="page"`. | | `disabled` | `boolean` | - | Disables the link, blocking all interactions. Removes `href` and sets `aria-disabled` on the `<a>` element. Takes precedence over `disabled` on `NavigationMenu.Root`. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeOnClick` | `boolean` | `false` | Whether to close the navigation menu when the link is clicked. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### NavigationMenu.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### NavigationMenu.TriggerPrimitive | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### NavigationMenu.TriggerIndicatorPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown as the indicator. Replaces the default chevron down icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### NavigationMenu.Content | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | `false` | Whether to keep the content mounted in the DOM while the popup is closed.
Ensures the content is present during server-side rendering for web crawlers. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### NavigationMenu.PortalPrimitive | Prop | Type | Default | Description | | ------------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `keepMounted` | `boolean` | `false` | Whether to keep the portal mounted in the DOM while the popup is hidden. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### NavigationMenu.PositionerPrimitive | Prop | Type | Default | Description | | ----------------------- | ----------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `align` | `center`, `end`, `start` | `center` | How to align the popup relative to the specified side. | | `alignOffset` | `number`, `function` | `0` | Additional offset along the alignment axis in pixels.
Also accepts a function that returns the offset to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `anchor` | `Element`, `VirtualElement`, `React.RefObject`, `function`, `null` | - | An element to position the popup against.
By default, the popup will be positioned against the trigger. | | `arrowPadding` | `number` | `5` | Minimum distance to maintain between the arrow and the edges of the popup.

Use it to prevent the arrow element from hanging out of the rounded corners of a popup. | | `collisionAvoidance` | `CollisionAvoidance` | - | Determines how to handle collisions when positioning the popup.

`side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):
- `'flip'`: keep the requested side when it fits; otherwise try the opposite side
(`top` and `bottom`, or `left` and `right`).
- `'shift'`: never change side; keep the requested side and move the popup within
the clipping boundary so it stays visible.
- `'none'`: do not correct side-axis overflow.

`align` controls overflow on the alignment axis (`start`/`center`/`end`):
- `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
- `'shift'`: keep side and requested alignment, then nudge the popup along the
alignment axis to fit.
- `'none'`: do not correct alignment-axis overflow.

`fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
preferred axis cannot fit:
- `'start'`: allow perpendicular fallback and try the logical start side first
(`top` before `bottom`, or `left` before `right` in LTR).
- `'end'`: allow perpendicular fallback and try the logical end side first
(`bottom` before `top`, or `right` before `left` in LTR).
- `'none'`: do not fallback to the perpendicular axis.

When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
If `align` is omitted, it defaults to `'flip'`. | | `collisionBoundary` | `Boundary` | `clipping-ancestors` | An element or a rectangle that delimits the area that the popup is confined to. | | `collisionPadding` | `Padding` | `5` | Additional space to maintain from the edge of the collision boundary. | | `disableAnchorTracking` | `boolean` | `false` | Whether to disable the popup from tracking any layout shift of its positioning anchor. | | `positionMethod` | `fixed`, `absolute` | `absolute` | Determines which CSS `position` property to use. | | `side` | `bottom`, `left`, `right`, `top`, `inline-end`, `inline-start` | `bottom` | Which side of the anchor element to align the popup against.
May automatically change to avoid collisions. | | `sideOffset` | `number`, `function` | `10` | Distance between the anchor and the popup in pixels.
Also accepts a function that returns the distance to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `sticky` | `boolean` | `false` | Whether to maintain the popup in the viewport after
the anchor element was scrolled out of view. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### NavigationMenu.PopupPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### NavigationMenu.Viewport | Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `popupElement` | `ReactElement` | - | Replaces the default `NavigationMenu.PopupPrimitive`. Use to change the panel that holds the content. | | `portalElement` | `ReactElement` | - | Replaces the default `NavigationMenu.PortalPrimitive`. Use to change the portal container. | | `positionerElement` | `ReactElement` | - | Replaces the default `NavigationMenu.PositionerPrimitive`. Use to change the side, alignment, or offset of the popup. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### NavigationMenu.ViewportPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Pagination URL: /docs/components/pagination Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/pagination/index.mdx Pagination은 콘텐츠를 페이지 단위로 탐색할 수 있도록 돕는 네비게이션 컴포넌트입니다. ```tsx import { Pagination } from '@vapor-ui/core'; export default function DefaultPagination() { return ( ); } ``` ## Property ### Sibling Count Pagination에서 현재 페이지 주변에 표시할 페이지 번호의 개수를 설정합니다. ```tsx import { Pagination, Text, VStack } from '@vapor-ui/core'; export default function PaginationSiblingCount() { return ( 1 Sibling 3 Sibling ); } ``` ### Boundary Count Pagination의 시작과 끝에 항상 표시할 페이지 번호의 개수를 설정합니다. ```tsx import { Pagination, Text, VStack } from '@vapor-ui/core'; export default function PaginationBoundaryCount() { return ( 1 Boundary 3 Boundary ); } ``` ### Disabled Pagination 버튼들의 비활성화 여부를 결정하는 옵션입니다. ```tsx import { Pagination } from '@vapor-ui/core'; export default function PaginationDisabled() { return ( ); } ``` ### Size Pagination의 크기를 설정합니다. ```tsx import { HStack, Pagination, Text, VStack } from '@vapor-ui/core'; export default function PaginationSize() { return ( sm md lg xl ); } ``` ## Examples ### Controlled Pagination 컴포넌트를 제어 컴포넌트로 사용하는 예시입니다. ```tsx import { useState } from 'react'; import { Button, HStack, Pagination, Text, VStack } from '@vapor-ui/core'; export default function PaginationControlled() { const [page, setPage] = useState(7); return ( Current Page is, {page} ); } ``` ## Props Table *** ### Pagination.Root | Prop | Type | Default | Description | | --------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **totalPages** | `number` | - | Total number of pages. `Pagination.Next` is disabled once this page is selected. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the pagination buttons and ellipsis, controlling width, height, and typography. | | `onPageChange` | `function` | - | Called when a page button, `Pagination.Previous`, or `Pagination.Next` is clicked, with the new page and the event details. Call `eventDetails.cancel()` to keep the current page. | | `boundaryCount` | `number` | - | Number of pages always shown at the start and the end of the range. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `defaultPage` | `number` | - | Page selected on first render, counted from `1`. Use when the component is not controlled. | | `disabled` | `boolean` | - | Disables the pagination, blocking all interactions on its buttons. | | `page` | `number` | - | Selected page, counted from `1`. Use when the component is controlled. | | `siblingCount` | `number` | - | Number of pages shown on each side of the selected page before the rest collapse into an ellipsis. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Pagination.RootPrimitive | Prop | Type | Default | Description | | --------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **totalPages** | `number` | - | Total number of pages. `Pagination.Next` is disabled once this page is selected. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the pagination buttons and ellipsis, controlling width, height, and typography. | | `onPageChange` | `function` | - | Called when a page button, `Pagination.Previous`, or `Pagination.Next` is clicked, with the new page and the event details. Call `eventDetails.cancel()` to keep the current page. | | `boundaryCount` | `number` | `1` | Number of pages always shown at the start and the end of the range. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `defaultPage` | `number` | `1` | Page selected on first render, counted from `1`. Use when the component is not controlled. | | `disabled` | `boolean` | `false` | Disables the pagination, blocking all interactions on its buttons. | | `page` | `number` | - | Selected page, counted from `1`. Use when the component is controlled. | | `siblingCount` | `number` | `2` | Number of pages shown on each side of the selected page before the rest collapse into an ellipsis. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Pagination.ListPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Pagination.Items | Prop | Type | Default | Description | | ---------- | ----------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode`, `function` | - | Content shown in place of the generated page buttons. As a function, receives the pages to show, each with a `type` (`NUM` for a page, `BREAK` for an ellipsis) and a page number in `value`. | #### Pagination.ItemPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Pagination.ButtonPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **page** | `number` | - | Page this button selects when clicked. The button is marked as current while this page is selected. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Pagination.EllipsisPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown for the skipped pages. Replaces the default more icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Pagination.Previous | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown inside the button. Replaces the default left chevron icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Pagination.PreviousPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown inside the button. Replaces the default left chevron icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Pagination.Next | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown inside the button. Replaces the default right chevron icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Pagination.NextPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown inside the button. Replaces the default right chevron icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Popover URL: /docs/components/popover Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/popover/index.mdx Popover는 트리거 요소 근처에 부가 정보나 상호작용 콘텐츠를 표시하는 오버레이 컴포넌트입니다. 툴팁, 메뉴, 폼, 상세 정보 등을 표시할 때 사용합니다. ```tsx 'use client'; import { Button, Popover } from '@vapor-ui/core'; export default function DefaultPopover() { return ( }>팝오버 열기 알림 새로운 메시지 3개와 알림 1개가 있습니다. ); } ``` ## Property *** ### PositionerProps Popover가 나타날 위치와 정렬을 설정합니다. ```tsx 'use client'; import { Button, HStack, Popover, Text, VStack } from '@vapor-ui/core'; export default function PopoverPositioning() { return ( Side top }> 상단 팝오버 상단 팝오버 트리거 위쪽에 표시되는 팝오버입니다. right }> 우측 팝오버 우측 팝오버 트리거 오른쪽에 표시되는 팝오버입니다. bottom }> 하단 팝오버 하단 팝오버 트리거 아래쪽에 표시되는 팝오버입니다. left }> 좌측 팝오버 좌측 팝오버 트리거 왼쪽에 표시되는 팝오버입니다. Alignment start }> 시작점 정렬 시작점 정렬 트리거의 시작점에 정렬된 팝오버입니다. center }> 중앙 정렬 중앙 정렬 트리거의 중앙에 정렬된 팝오버입니다. end }> 끝점 정렬 끝점 정렬 트리거의 끝점에 정렬된 팝오버입니다. ); } ``` ### Offset Popover와 트리거 간의 거리를 조정합니다. ```tsx 'use client'; import { Button, HStack, Popover, Text, VStack } from '@vapor-ui/core'; export default function PopoverOffset() { return ( default }> 기본 오프셋 기본 오프셋 기본 8px 오프셋이 적용된 팝오버입니다. sideOffset 16 }> 사이드 오프셋 16px 사이드 오프셋 16px 트리거로부터 16px 떨어진 팝오버입니다. alignOffset 100 }> 정렬 오프셋 100px 정렬 오프셋 100px 정렬 축에서 100px 이동한 팝오버입니다. combined }> 복합 오프셋 복합 오프셋 사이드 24px, 정렬 -100px 오프셋이 적용된 팝오버입니다. ); } ``` ## Examples *** ### Content Variations 간단한 텍스트부터 복잡한 상호작용 요소까지 다양한 콘텐츠를 표시합니다. ```tsx 'use client'; import { Button, HStack, Popover, Text, VStack } from '@vapor-ui/core'; export default function PopoverPopup() { return ( text }> 간단한 텍스트 간단한 팝오버 메시지입니다. title + desc }> 제목과 설명 알림 새로운 업데이트가 있습니다. 확인해보세요. interactive }> 상호작용 콘텐츠 설정 원하는 설정을 선택하세요. 옵션 1 } /> 옵션 2 } /> ); } ``` ## Props Table *** ### Popover.Root | Prop | Type | Default | Description | | ---------------------- | ----------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultOpen` | `boolean` | `false` | Whether the popover is initially open.

To render a controlled popover, use the `open` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the popover is opened or closed. | | `open` | `boolean` | - | Whether the popover is currently open. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the popover.
Call this after any externally controlled closing animation finishes.
- `close`: Closes the popover imperatively when called. | | `children` | `ReactNode`, `function` | - | The content of the popover.
This can be a regular React node or a render function that receives the `payload` of the active trigger. | | `defaultTriggerId` | `string`, `null` | - | ID of the trigger that the popover is associated with.
This is useful in conjunction with the `defaultOpen` prop to create an initially open popover. | | `handle` | `PopoverHandle` | - | A handle to associate the popover with a trigger.
If specified, allows external triggers to control the popover's open state. | | `modal` | `boolean`, `trap-focus` | `false` | Determines if the popover enters a modal state when open.
- `true`: user interaction is limited to the popover: document page scroll is locked, and pointer interactions on outside elements are disabled.
- `false`: user interaction with the rest of the document is allowed.
- `'trap-focus'`: focus is trapped inside the popover, but document page scroll is not locked and pointer interactions outside of it remain enabled.

On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior.

When `modal` is `true`, focus trapping is enabled only if `<Popover.Close>` is rendered
inside `<Popover.Popup>`. It can be visually hidden with your own CSS if needed, such as
Tailwind's `sr-only` utility.

When `modal` is `'trap-focus'`, render `<Popover.Close>` inside `<Popover.Popup>` so touch
screen readers can escape the popup. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the popover is opened or closed. | | `triggerId` | `string`, `null` | - | ID of the trigger that the popover is associated with.
This is useful in conjunction with the `open` prop to create a controlled popover.
There's no need to specify this prop when the popover is uncontrolled (that is, when the `open` prop is not set). | ### Popover.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `closeDelay` | `number` | `0` | How long to wait before closing the popover that was opened on hover.
Specified in milliseconds.

Requires the `openOnHover` prop. | | `delay` | `number` | `300` | How long to wait before the popover may be opened on hover. Specified in milliseconds.

Requires the `openOnHover` prop. | | `handle` | `PopoverHandle` | - | A handle to associate the trigger with a popover. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `openOnHover` | `boolean` | `false` | Whether the popover should also open when the trigger is hovered. | | `payload` | `unknown` | - | A payload to pass to the popover when it is opened. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Popover.Popup | Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `portalElement` | `ReactElement` | - | Replaces the default `Popover.PortalPrimitive`. Use to change the portal container. | | `positionerElement` | `ReactElement` | - | Replaces the default `Popover.PositionerPrimitive`. Use to change the side, alignment, or offset of the popup. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is opened.
By default, focus moves to the first tabbable element inside the popup, except when the popover
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Popover.PortalPrimitive | Prop | Type | Default | Description | | ------------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `keepMounted` | `boolean` | `false` | Whether to keep the portal mounted in the DOM while the popup is hidden. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Popover.PositionerPrimitive | Prop | Type | Default | Description | | ----------------------- | ----------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `align` | `center`, `end`, `start` | `center` | How to align the popup relative to the specified side. | | `alignOffset` | `number`, `function` | `0` | Additional offset along the alignment axis in pixels.
Also accepts a function that returns the offset to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `anchor` | `Element`, `VirtualElement`, `React.RefObject`, `function`, `null` | - | An element to position the popup against.
By default, the popup will be positioned against the trigger. | | `arrowPadding` | `number` | `5` | Minimum distance to maintain between the arrow and the edges of the popup.

Use it to prevent the arrow element from hanging out of the rounded corners of a popup. | | `collisionAvoidance` | `CollisionAvoidance` | - | Determines how to handle collisions when positioning the popup.

`side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):
- `'flip'`: keep the requested side when it fits; otherwise try the opposite side
(`top` and `bottom`, or `left` and `right`).
- `'shift'`: never change side; keep the requested side and move the popup within
the clipping boundary so it stays visible.
- `'none'`: do not correct side-axis overflow.

`align` controls overflow on the alignment axis (`start`/`center`/`end`):
- `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
- `'shift'`: keep side and requested alignment, then nudge the popup along the
alignment axis to fit.
- `'none'`: do not correct alignment-axis overflow.

`fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
preferred axis cannot fit:
- `'start'`: allow perpendicular fallback and try the logical start side first
(`top` before `bottom`, or `left` before `right` in LTR).
- `'end'`: allow perpendicular fallback and try the logical end side first
(`bottom` before `top`, or `right` before `left` in LTR).
- `'none'`: do not fallback to the perpendicular axis.

When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
If `align` is omitted, it defaults to `'flip'`. | | `collisionBoundary` | `Boundary` | `clipping-ancestors` | An element or a rectangle that delimits the area that the popup is confined to. | | `collisionPadding` | `Padding` | `5` | Additional space to maintain from the edge of the collision boundary. | | `disableAnchorTracking` | `boolean` | `false` | Whether to disable the popup from tracking any layout shift of its positioning anchor. | | `positionMethod` | `fixed`, `absolute` | `absolute` | Determines which CSS `position` property to use. | | `side` | `bottom`, `left`, `right`, `top`, `inline-end`, `inline-start` | `bottom` | Which side of the anchor element to align the popup against.
May automatically change to avoid collisions. | | `sideOffset` | `number`, `function` | `10` | Distance between the anchor and the popup in pixels.
Also accepts a function that returns the distance to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `sticky` | `boolean` | `false` | Whether to maintain the popup in the viewport after
the anchor element was scrolled out of view. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Popover.PopupPrimitive | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the popover is opened.
By default, focus moves to the first tabbable element inside the popup, except when the popover
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Popover.Title | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Popover.Description | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Popover.Close | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # ProgressBar URL: /docs/components/progress-bar Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/progress-bar/index.mdx ProgressBar는 시작과 끝이 있는 작업의 진행 정도를 보여줍니다. 디스크 사용량이나 점수처럼 고정된 척도의 측정값에는 Meter를 사용합니다. ```tsx import { ProgressBar } from '@vapor-ui/core'; export default function DefaultProgressBar() { return ( 파일 업로드 ); } ``` ## Property *** ### Size Track의 높이를 설정합니다. ```tsx import { ProgressBar, VStack } from '@vapor-ui/core'; export default function ProgressBarSize() { return ( {(['sm', 'md', 'lg'] as const).map((size) => ( {size} ))} ); } ``` ### Type 작업의 상태를 나타냅니다. ```tsx import { ProgressBar, VStack } from '@vapor-ui/core'; export default function ProgressBarType() { return ( report.pdf 업로드 10MB 중 4.2MB를 전송했습니다. report.pdf 업로드 업로드에 실패했습니다. 파일이 10MB를 넘습니다. ); } ``` ### Value Text `ProgressBar.Value`는 선언한 범위를 기준으로 값을 백분율로 환산해 보여줍니다. 백분율 대신 다른 표현이 필요하면 두 곳을 함께 바꿉니다. `getAriaValueText`는 보조기기가 듣는 `aria-valuetext`를, `ProgressBar.Value`의 `children` 함수는 화면 텍스트를 정합니다. 한쪽만 바꾸면 보는 사람과 듣는 사람이 다른 값을 받습니다. ```tsx import { ProgressBar, VStack } from '@vapor-ui/core'; export default function ProgressBarValueText() { return ( 디스크 검사 `8개 중 ${value}개`} > 파일 업로드 {(_, value) => `8개 중 ${value}개`} ); } ``` ### Indeterminate `value`가 `null`이면 진행률을 알 수 없는 상태입니다. 40% 폭의 세그먼트가 Track을 한 방향으로 훑고, `aria-valuenow`는 쓰이지 않습니다. ```tsx import { ProgressBar } from '@vapor-ui/core'; export default function ProgressBarIndeterminate() { return ( 서버 응답 대기 중 {() => '처리 중'} ); } ``` ## Examples *** ### Description `ProgressBar.Description`은 진행 상황을 말로 풀어 씁니다. 남은 용량, 실패 사유, 다음에 할 일 같은 내용입니다. `ProgressBar.Root`의 `type`이 `error`이면 이 텍스트가 danger 색이 되고 막대는 danger 색으로 끝까지 찹니다. 단계마다 다른 문구가 필요하면 `render`나 `className` 함수의 두 번째 인수 `state.status`를 보세요. 값이 없으면 `indeterminate`, 최댓값에 닿으면 `complete`, 그 사이는 `progressing`입니다. ```tsx 'use client'; import { useState } from 'react'; import { Button, ProgressBar, VStack } from '@vapor-ui/core'; export default function ProgressBarDescription() { const [failed, setFailed] = useState(false); return ( report.pdf 업로드 {failed ? '업로드에 실패했습니다. 파일이 10MB를 넘습니다.' : '10MB 중 4.2MB를 전송했습니다.'} ); } ``` ## Accessibility *** * `ProgressBar.Label`을 넣거나 `ProgressBar.Root`에 `aria-label` 또는 `aria-labelledby`를 주세요. 이름이 없으면 보조기기가 숫자만 읽습니다. 개발 모드에서는 콘솔 경고가 나옵니다. * 실패 사유나 다음 행동은 `ProgressBar.Description`에 적으세요. **`type="error"`는 겉모습만 바꿉니다.** 실패했다는 사실은 문구가 직접 말해야 합니다. 색과 꽉 찬 막대만으로는 스크린 리더 사용자도, 빨강과 회색을 구별하지 못하는 사용자도 실패를 알 수 없습니다. * 진행 상황을 막대 길이만으로 전달하지 마세요. `ProgressBar.Value`나 `ProgressBar.Description`으로 텍스트를 함께 두면 확대 화면이나 저시력 환경에서도 값을 읽을 수 있습니다. ## Props Table *** ### ProgressBar.Root | Prop | Type | Default | Description | | ------------------ | --------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `number`, `null` | - | The current value. The component is indeterminate when value is `null`. | | `size` | `sm`, `md`, `lg` | `md` | Size of the track. Controls its height. | | `type` | `default`, `error` | `default` | Tone of the description text. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `aria-valuetext` | `string` | - | A string value that provides a user-friendly name for `aria-valuenow`, the current value of the progress bar. | | `format` | `Intl.NumberFormatOptions` | - | Options to format the value. | | `getAriaValueText` | `function` | - | Accepts a function which returns a string value that provides a human-readable text alternative for the current value of the progress bar. | | `locale` | `Intl.LocalesArgument` | - | The locale used by `Intl.NumberFormat` when formatting the value.
Defaults to the user's runtime locale. | | `max` | `number` | `100` | The maximum value. | | `min` | `number` | `0` | The minimum value. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### ProgressBar.Label | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### ProgressBar.Value | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `children` | `function`, `null` | - | | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### ProgressBar.Track | Prop | Type | Default | Description | | ------------------ | --------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `indicatorElement` | `ReactElement` | - | Replaces the `ProgressBar.IndicatorPrimitive` rendered inside the track by default. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### ProgressBar.TrackPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### ProgressBar.IndicatorPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### ProgressBar.Description | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Radio URL: /docs/components/radio Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/radio/index.mdx Radio는 여러 옵션 중 하나만 선택할 수 있는 입력 컴포넌트입니다. RadioGroup과 함께 사용하여 라디오 버튼 그룹을 구성할 수 있습니다. ```tsx import { HStack, Radio, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function DefaultRadioGroup() { return ( } typography="body2"> Apple } typography="body2"> Orange } typography="body2"> Banana (Disabled) ); } ``` ## Property *** ### Size RadioGroup의 크기를 설정합니다. ```tsx import { HStack, Radio, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioGroupSize() { return ( md } typography="body2"> Medium Option 1 } typography="body2"> Medium Option 2 lg } typography="body2"> Large Option 1 } typography="body2"> Large Option 2 ); } ``` ### Disabled RadioGroup의 비활성화 상태를 설정합니다. ```tsx import { HStack, Radio, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioGroupDisabled() { return ( individual item disabled } typography="body2"> Option 1 (Default) } typography="body2"> Option 2 (Default) } typography="body2"> Option 3 (Disabled) group disabled } typography="body2"> Group 1 } typography="body2"> Group 2 } typography="body2"> Group 3 ); } ``` ### Read Only RadioGroup의 읽기 전용 상태입니다. 사용자가 값을 변경할 수 없지만 현재 선택된 상태를 확인할 수 있습니다. ```tsx import { HStack, Radio, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioReadOnly() { return ( } typography="body2"> Read Only (Selected) } typography="body2"> Read Only (Unselected) ); } ``` ## Examples *** ### Direction Radio 그룹의 방향을 조절할 수 있습니다. VStack과 HStack을 사용하여 세로 및 가로 방향으로 배치할 수 있습니다. ```tsx import { HStack, Radio, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioDirection() { return ( vertical } typography="body2"> Option 1 } typography="body2"> Option 2 } typography="body2"> Option 3 horizontal } typography="body2"> Option 1 } typography="body2"> Option 2 } typography="body2"> Option 3 ); } ``` ### Flexible Radio의 유연한 사용예시입니다. ```tsx import { HStack, Radio, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function Flexible() { return ( Vertical } typography="body2"> Option 1 } typography="body2"> Option 2 } typography="body2"> Option 3 ); } ``` ## Props Table *** ### RadioGroup.Root | Prop | Type | Default | Description | | --------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | `md`, `lg` | `md` | Size of the radios in the group, controlling their width and height. A `Radio.Root` that sets its own `size` keeps it. | | `defaultValue` | `unknown` | - | The uncontrolled value of the radio button that should be initially selected.

To render a controlled radio group, use the `value` prop instead. | | `onValueChange` | `function` | - | Callback fired when the value changes. | | `value` | `unknown` | - | The controlled value of the radio item that should be currently selected.

To render an uncontrolled radio group, use the `defaultValue` prop instead. | | `children` | `ReactNode` | - | Radios shown in the group, such as `Radio.Root` or `RadioCard` items and an optional `RadioGroup.Label`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `invalid` | `boolean` | - | Marks the radio group as invalid, applying error styles to every radio and radio card inside it. Sets `aria-invalid` on the `<div>` element. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `form` | `string` | - | Identifies the form that owns the radio inputs.
Useful when the radio group is rendered outside the form. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `name` | `string` | - | Identifies the field when a form is submitted. | | `readOnly` | `boolean` | `false` | Whether the user should be unable to select a different radio button in the group. | | `required` | `boolean` | `false` | Whether the user must choose a value before submitting a form. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### RadioGroup.Label | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Text of the label, such as the question the radios answer. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Radio.Root | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **value** | `unknown` | - | The unique identifying value of the radio in a group. | | `invalid` | `boolean` | `false` | Marks the radio as invalid, applying error styles. Sets `aria-invalid` on the `<span>` element. Inside an invalid `RadioGroup.Root`, the radio is always invalid. | | `size` | `md`, `lg` | `md` | Size of the radio, controlling its width and height. Inside `RadioGroup.Root`, falls back to the group's `size` when not set. | | `children` | `ReactNode` | - | Element shown inside the radio in place of the default `Radio.IndicatorPrimitive`, such as a `Radio.IndicatorPrimitive` with custom props. Anything other than a single element is ignored and the default indicator is shown. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `readOnly` | `boolean` | - | Whether the user should be unable to select the radio button. | | `required` | `boolean` | - | Whether the user must choose a value before submitting a form. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Radio.IndicatorPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | `true` | Whether to keep the HTML element in the DOM when the radio button is inactive. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # RadioCard URL: /docs/components/radio-card Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/radio-card/index.mdx RadioCard는 RadioGroup과 함께 사용하는 카드 형태의 라디오 버튼 컴포넌트입니다. 선택 가능한 옵션을 카드 UI로 표현하여 더 직관적인 사용자 경험을 제공합니다. ```tsx import { HStack, RadioCard, RadioGroup } from '@vapor-ui/core'; export default function DefaultRadioCard() { return ( Light Theme Dark Theme System (Disabled) ); } ``` ## Property *** ### Disabled 사용자가 상호작용할 수 없는 상태입니다. 액션을 수행하기 위한 특정 조건을 충족하지 않았거나 일시적으로 기능을 제한하려는 상황에서 사용합니다. ```tsx import { HStack, RadioCard, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioCardDisabled() { return ( group disabled Option 1 Option 2 Option 3 individual card disabled Enabled Option Disabled Option Another Enabled Option ); } ``` ### Read Only 읽기 전용 상태로, 사용자가 값을 변경할 수 없지만 현재 선택된 상태를 확인할 수 있습니다. ```tsx import { HStack, RadioCard, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioCardReadonly() { return ( readOnly Unselected Option Selected Option (Read Only) Another Option normal Unselected Option Selected Option (Editable) Another Option ); } ``` ## Examples *** ### Simple Usage RadioGroup.Root와 함께 사용합니다. ```tsx import { useState } from 'react'; import { HStack, RadioCard, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioCardSimple() { const [value, setValue] = useState('option1'); return ( Selected: {value} setValue(newValue as string)} > First Option Second Option Third Option ); } ``` ### Direction VStack과 HStack을 사용하여 세로 및 가로 방향으로 배치합니다. ```tsx import { HStack, RadioCard, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioCardDirection() { return ( vertical Option 1 Option 2 Option 3 horizontal Option 1 Option 2 Option 3 ); } ``` ### With Rich Content RadioCard는 고정된 높이가 없어 다양한 콘텐츠를 포함할 수 있습니다. 텍스트, 아이콘, 가격 정보 등 복잡한 레이아웃을 자유롭게 구성할 수 있습니다. ```tsx import { useState } from 'react'; import { HStack, RadioCard, RadioGroup, Text, VStack } from '@vapor-ui/core'; export default function RadioCardWithContent() { const [value, setValue] = useState('basic'); return (
선택된 플랜: {value} setValue(newValue as string)} > Basic $9/month 5 projects included Pro $29/month Unlimited projects Enterprise Custom pricing Advanced features
); } ```
## Props Table *** ### RadioCard | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `unknown` | - | The unique identifying value of the radio in a group. | | `invalid` | `boolean` | `false` | Marks the radio card as invalid, applying error styles. Sets `aria-invalid` on the `<span>` element. Inside an invalid `RadioGroup.Root`, the card is always invalid. | | `children` | `ReactNode` | - | Content shown inside the card, such as a label or a short description of the option. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `readOnly` | `boolean` | - | Whether the user should be unable to select the radio button. | | `required` | `boolean` | - | Whether the user must choose a value before submitting a form. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # SegmentedControl URL: /docs/components/segmented-control Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/segmented-control/index.mdx 같은 콘텐츠 영역 내에서 화면의 보기 방식이나 필터를 제어합니다. ```tsx import { SegmentedControl } from '@vapor-ui/core'; export default function DefaultSegmentedControl() { return ( 전체 진행 중 완료 예정 ); } ``` 주의! * `SegmentedControl.Root`의 `defaultValue`를 지정하지 않으면 첫 번째 아이템이 자동 선택됩니다. * `SegmentedControl.Item`의 `value=""` 속성에는 **반드시 아이템의 역할을 설명할 수 있는 이름**을 사용하세요. ## Property *** ### Size SegmentedControl의 크기를 설정합니다. ```tsx import { SegmentedControl, VStack } from '@vapor-ui/core'; export default function SegmentedControlSize() { return ( SM Test MD Test LG Test ); } ``` ### Controlled State SegmentedControl의 선택 상태를 외부에서 제어합니다. ```tsx import { useState } from 'react'; import { Button, HStack, SegmentedControl, VStack } from '@vapor-ui/core'; import { DarkIcon, LightIcon, PcIcon } from '@vapor-ui/icons'; export default function DefaultSegmentedControl() { const [mode, setMode] = useState('light'); return ( 현재 모드: {mode} Light Dark System ); } ``` ### Disabled SegmentedControl의 비활성 상태를 설정합니다. ```tsx import { SegmentedControl } from '@vapor-ui/core'; export default function DefaultSegmentedControl() { return ( 전체 진행 중 완료 예정 ); } ``` ## Examples *** ### Icon Item `SegmentedControl.IconItem`을 이용하여 아이콘만 포함하는 아이템을 사용할 수 있습니다. 이 경우, 각 아이템에 `aria-label`로 접근 가능한 이름을 제공하거나, 툴팁으로 보조 설명을 추가하는 것을 권장합니다. ```tsx import { SegmentedControl, Tooltip, VStack } from '@vapor-ui/core'; import { DarkIcon, LightIcon, PcIcon } from '@vapor-ui/icons'; export default function DefaultSegmentedControl() { return ( } /> 라이트 모드 } /> 다크 모드 } /> 시스템 모드 ); } ``` ## Props Table *** ### SegmentedControl.Root | Prop | Type | Default | Description | | ------------------ | -------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | `sm`, `md`, `lg` | `md` | Size of the segmented control, controlling its padding and the height and padding of its segments. | | `defaultValue` | `string` | - | Value of the segment selected on first render, for an uncontrolled segmented control. Must match the `value` of a `SegmentedControl.Item`. When it is not set or matches no segment, the first enabled segment is selected. | | `onValueChange` | `function` | - | Called when the user selects a different segment by clicking it or with the arrow keys. Receives the new value and the change event details. | | `value` | `string` | - | Value of the selected segment, for a controlled segmented control. Use with `onValueChange` to update it when the user selects a segment. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `indicatorElement` | `ReactElement` | - | Replaces the default `SegmentedControl.IndicatorPrimitive`. Use to change the look of the sliding highlight. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `form` | `string` | - | Identifies the form that owns the radio inputs.
Useful when the radio group is rendered outside the form. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `name` | `string` | - | Identifies the field when a form is submitted. | | `readOnly` | `boolean` | `false` | Whether the user should be unable to select a different radio button in the group. | | `required` | `boolean` | `false` | Whether the user must choose a value before submitting a form. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### SegmentedControl.RootPrimitive | Prop | Type | Default | Description | | --------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | `sm`, `md`, `lg` | `md` | Size of the segmented control, controlling its padding and the height and padding of its segments. | | `defaultValue` | `string` | - | Value of the segment selected on first render, for an uncontrolled segmented control. Must match the `value` of a `SegmentedControl.Item`. When it is not set or matches no segment, the first enabled segment is selected. | | `onValueChange` | `function` | - | Called when the user selects a different segment by clicking it or with the arrow keys. Receives the new value and the change event details. | | `value` | `string` | - | Value of the selected segment, for a controlled segmented control. Use with `onValueChange` to update it when the user selects a segment. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `form` | `string` | - | Identifies the form that owns the radio inputs.
Useful when the radio group is rendered outside the form. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `name` | `string` | - | Identifies the field when a form is submitted. | | `readOnly` | `boolean` | `false` | Whether the user should be unable to select a different radio button in the group. | | `required` | `boolean` | `false` | Whether the user must choose a value before submitting a form. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### SegmentedControl.IndicatorPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### SegmentedControl.Item | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `string` | - | Value that identifies the segment when it is selected. Must be unique within the segmented control. | | `children` | `ReactNode` | - | Content shown inside the segment, such as a label or an icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `readOnly` | `boolean` | - | Whether the user should be unable to select the radio button. | | `required` | `boolean` | - | Whether the user must choose a value before submitting a form. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### SegmentedControl.IconItem | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `string` | - | Value that identifies the segment when it is selected. Must be unique within the segmented control. | | `children` | `ReactNode` | - | Content shown inside the segment, such as a label or an icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `readOnly` | `boolean` | - | Whether the user should be unable to select the radio button. | | `required` | `boolean` | - | Whether the user must choose a value before submitting a form. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Select URL: /docs/components/select Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/select/index.mdx Select는 사용자가 여러 옵션 중에서 하나를 선택할 수 있는 드롭다운 컴포넌트입니다. 폼 입력, 설정 선택, 필터링 등에 사용되며, 키보드 내비게이션과 접근성을 완벽하게 지원합니다. ```tsx import { Select } from '@vapor-ui/core'; const fonts = [ { label: 'Sans-serif', value: 'sans-serif' }, { label: 'Serif', value: 'serif' }, { label: 'Monospace', value: 'mono' }, { label: 'Cursive', value: 'cursive' }, ]; export default function DefaultSelect() { return ( 폰트 {fonts.map((font) => ( {font.label} ))} ); } ``` ## Property *** ### Size Select의 크기를 설정합니다. ```tsx import { HStack, Select, Text, VStack } from '@vapor-ui/core'; export default function SelectSize() { return ( sm md lg xl ); } const SelectTemplate = (props: Select.Root.Props) => { return ( 옵션 1 옵션 2 ); }; ``` ### Positioning Select 드롭다운이 나타날 위치를 설정합니다. 기본값은 'bottom'입니다. ```tsx import { HStack, Select } from '@vapor-ui/core'; export default function SelectPositioning() { return ( 옵션 1 옵션 2 옵션 1 옵션 2 옵션 1 옵션 2 옵션 1 옵션 2 ); } ``` ### Controlled State Select의 선택 상태를 외부에서 제어합니다. ```tsx 'use client'; import { useState } from 'react'; import { Button, HStack, Select, Text, VStack } from '@vapor-ui/core'; const fonts = [ { label: 'Sans-serif', value: 'sans-serif' }, { label: 'Serif', value: 'serif' }, { label: 'Monospace', value: 'mono' }, { label: 'Cursive', value: 'cursive' }, ]; export default function SelectControlled() { const [value, setValue] = useState(fonts[0].value); const handleValueChange = (newValue: unknown) => { setValue(newValue as string); }; return ( 폰트 {fonts.map((font) => ( {font.label} ))} 선택된 값: {value || '없음'} ); } ``` ### States Select의 다양한 상태(비활성화, 읽기 전용, 오류)를 설정합니다. ```tsx import { HStack, Select, Text, VStack } from '@vapor-ui/core'; export default function SelectStates() { return ( default disabled readOnly invalid ); } const SelectTemplate = (props: Select.Root.Props) => { return ( 옵션 1 옵션 2 ); }; ``` ## Examples *** ### Items Configuration 배열 형태와 객체 형태의 아이템 데이터를 모두 지원합니다. ```tsx import { Select, Text, VStack } from '@vapor-ui/core'; const fonts = [ { label: 'Sans-serif', value: 'sans' }, { label: 'Serif', value: 'serif' }, { label: 'Monospace', value: 'mono' }, { label: 'Cursive', value: 'cursive' }, ]; const languages = { javascript: 'JavaScript', typescript: 'TypeScript', python: 'Python', java: 'Java', go: 'Go', }; export default function SelectItems() { return ( 배열 형태의 아이템 폰트 {fonts.map((font) => ( {font.label} ))} 객체 형태의 아이템 프로그래밍 언어 {Object.entries(languages).map(([value, label]) => ( {label} ))} ); } ``` ### Grouping Options 관련된 옵션들을 그룹으로 묶어 구조화할 수 있습니다. Group과 GroupLabel, Separator를 사용하여 명확한 구조를 만들 수 있습니다. ```tsx import { Select, VStack } from '@vapor-ui/core'; export default function SelectGrouping() { return ( 프론트엔드 React Vue Angular 백엔드 Node.js Python Java 데이터베이스 MySQL PostgreSQL MongoDB ); } ``` ### Custom Value Display Select.Value에 함수형 children을 제공하여 선택된 값을 커스터마이징할 수 있습니다. ```tsx import { Select, Text, VStack } from '@vapor-ui/core'; const fonts = { sans: 'Sans-serif', serif: 'Serif', mono: 'Monospace', cursive: 'Cursive', }; const renderValue = (value: string) => { if (!value) return '선택된 폰트 없음'; return {fonts[value as keyof typeof fonts]}; }; export default function SelectCustomValue() { return ( 커스텀 값 표시 {renderValue} {Object.entries(fonts).map(([value, label]) => ( {label} ))} ); } ``` ## Props Table *** ### Select.Root | Prop | Type | Default | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid` | `boolean` | `false` | Marks the select as invalid, applying error styles. Sets `aria-invalid` on the trigger `<button>` element. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the select, controlling height, padding, typography, and icon size. | | `defaultOpen` | `boolean` | `false` | Whether the select popup is initially open.

To render a controlled select popup, use the `open` prop instead. | | `defaultValue` | `Value`, `null` | - | The uncontrolled value of the select when it's initially rendered.

To render a controlled select, use the `value` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the select popup is opened or closed. | | `onValueChange` | `function` | - | Event handler called when the value of the select changes. | | `open` | `boolean` | - | Whether the select popup is currently open. | | `value` | `Value`, `null` | - | The value of the select. Use when controlled. | | `children` | `ReactNode` | - | Parts of the select, such as `Select.Trigger` and `Select.Popup`. | | `placeholder` | `ReactNode` | - | Text shown in the trigger when no value is selected. The `children` of `Select.ValuePrimitive`, or the label of an item whose value is `null` in `items`, takes precedence over it. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the select.
Call this after any externally controlled closing animation finishes. | | `autoComplete` | `string` | - | Provides a hint to the browser for autofill. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `form` | `string` | - | Identifies the form that owns the hidden input.
Useful when the select is rendered outside the form. | | `highlightItemOnHover` | `boolean` | `true` | Whether moving the pointer over items should highlight them.
Disabling this prop allows CSS `:hover` to be differentiated from the `:focus` (`data-highlighted`) state. | | `id` | `string` | - | The id of the Select. | | `inputRef` | `React.Ref` | - | A ref to access the hidden input element. | | `isItemEqualToValue` | `function` | - | Custom comparison logic used to determine if a select item value matches the current selected value. Useful when item values are objects without matching referentially.
Defaults to `Object.is` comparison. | | `items` | `Record`, `readonly { label: React.ReactNode; value: any; }[]`, `readonly Group[]` | - | Data structure of the items rendered in the select popup.
When specified, `<Select.Value>` renders the label of the selected item instead of the raw value. | | `itemToStringLabel` | `function` | - | When the item values are objects (`<Select.Item value={object}>`), this function converts the object value to a string representation for display in the trigger.
If the shape of the object is `{ value, label }`, the label will be used automatically without needing to specify this prop. | | `itemToStringValue` | `function` | - | When the item values are objects (`<Select.Item value={object}>`), this function converts the object value to a string representation for form submission.
If the shape of the object is `{ value, label }`, the value will be used automatically without needing to specify this prop. | | `modal` | `boolean` | `true` | Determines if the select enters a modal state when open.
- `true`: user interaction is limited to the select: document page scroll is locked and pointer interactions on outside elements are disabled.
- `false`: user interaction with the rest of the document is allowed.

On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior. | | `name` | `string` | - | Identifies the field when a form is submitted. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the select popup is opened or closed. | | `readOnly` | `boolean` | `false` | Whether the user should be unable to choose a different option from the select popup. | | `required` | `boolean` | `false` | Whether the user must choose a value before submitting a form. | ### Select.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Not rendered: the trigger always shows the selected value and a chevron icon. Use `Select.TriggerPrimitive` to compose custom content. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.TriggerPrimitive | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Content shown inside the trigger, such as `Select.ValuePrimitive` and `Select.TriggerIconPrimitive`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the component should ignore user interaction. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | `<button />` | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.ValuePrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `children` | `ReactNode`, `function` | - | Accepts a function that returns a `ReactNode` to format the selected value.
Treat the value as read-only: in `multiple` mode it may be a shared frozen array
when nothing is selected. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.PlaceholderPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.TriggerIconPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown in place of the default chevron icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Select.Popup | Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `children` | `ReactNode` | - | Options shown in the popup, such as `Select.Item`, `Select.Group`, or `Select.Separator`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `portalElement` | `ReactElement` | - | Replaces the default `Select.PortalPrimitive`. Use to change the portal container. | | `positionerElement` | `ReactElement` | - | Replaces the default `Select.PositionerPrimitive`. Use to change the side, alignment, or offset of the popup. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the select popup is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.PortalPrimitive | Prop | Type | Default | Description | | ----------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.PositionerPrimitive | Prop | Type | Default | Description | | ----------------------- | ----------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `align` | `center`, `end`, `start` | `start` | How to align the popup relative to the specified side. | | `alignItemWithTrigger` | `boolean` | `false` | Whether the positioner overlaps the trigger so the selected item's text is aligned with the trigger's value text. This only applies to mouse input and is automatically disabled if there is not enough space. | | `alignOffset` | `number`, `function` | `0` | Additional offset along the alignment axis in pixels.
Also accepts a function that returns the offset to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `anchor` | `Element`, `VirtualElement`, `React.RefObject`, `function`, `null` | - | An element to position the popup against.
By default, the popup will be positioned against the trigger. | | `arrowPadding` | `number` | `5` | Minimum distance to maintain between the arrow and the edges of the popup.

Use it to prevent the arrow element from hanging out of the rounded corners of a popup. | | `collisionAvoidance` | `CollisionAvoidance` | - | Determines how to handle collisions when positioning the popup.

`side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):
- `'flip'`: keep the requested side when it fits; otherwise try the opposite side
(`top` and `bottom`, or `left` and `right`).
- `'shift'`: never change side; keep the requested side and move the popup within
the clipping boundary so it stays visible.
- `'none'`: do not correct side-axis overflow.

`align` controls overflow on the alignment axis (`start`/`center`/`end`):
- `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
- `'shift'`: keep side and requested alignment, then nudge the popup along the
alignment axis to fit.
- `'none'`: do not correct alignment-axis overflow.

`fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
preferred axis cannot fit:
- `'start'`: allow perpendicular fallback and try the logical start side first
(`top` before `bottom`, or `left` before `right` in LTR).
- `'end'`: allow perpendicular fallback and try the logical end side first
(`bottom` before `top`, or `right` before `left` in LTR).
- `'none'`: do not fallback to the perpendicular axis.

When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
If `align` is omitted, it defaults to `'flip'`. | | `collisionBoundary` | `Boundary` | `clipping-ancestors` | An element or a rectangle that delimits the area that the popup is confined to. | | `collisionPadding` | `Padding` | `5` | Additional space to maintain from the edge of the collision boundary. | | `disableAnchorTracking` | `boolean` | `false` | Whether to disable the popup from tracking any layout shift of its positioning anchor. | | `positionMethod` | `fixed`, `absolute` | `absolute` | Determines which CSS `position` property to use. | | `side` | `bottom`, `left`, `right`, `top`, `inline-end`, `inline-start` | `bottom` | Which side of the anchor element to align the popup against.
May automatically change to avoid collisions. | | `sideOffset` | `number`, `function` | `4` | Distance between the anchor and the popup in pixels.
Also accepts a function that returns the distance to read the dimensions of the anchor
and positioner elements, along with its side and alignment.

The function takes a `data` object parameter with the following properties:
- `data.anchor`: the dimensions of the anchor element with properties `width` and `height`.
- `data.positioner`: the dimensions of the positioner element with properties `width` and `height`.
- `data.side`: which side of the anchor element the positioner is aligned against.
- `data.align`: how the positioner is aligned relative to the specified side. | | `sticky` | `boolean` | `false` | Whether to maintain the popup in the viewport after
the anchor element was scrolled out of view. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.PopupPrimitive | Prop | Type | Default | Description | | ------------ | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `children` | `ReactNode` | - | Options shown in the popup, such as `Select.Item`, `Select.Group`, or `Select.Separator`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the select popup is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Select.Item | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` | `any` | `null` | A unique value that identifies this select item. | | `children` | `ReactNode` | - | Label of the option, such as its text or an icon with text. The check mark is added after it. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Specifies the text label to use when the item is matched during keyboard text navigation.

Defaults to the item text content if not provided. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.ItemPrimitive | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` | `any` | `null` | A unique value that identifies this select item. | | `children` | `ReactNode` | - | Content shown inside the option, such as its label and `Select.ItemIndicatorPrimitive`. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `label` | `string` | - | Specifies the text label to use when the item is matched during keyboard text navigation.

Defaults to the item text content if not provided. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Select.ItemIndicatorPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `children` | `ReactNode` | - | Icon shown in place of the default check icon. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | - | Whether to keep the HTML element in the DOM when the item is not selected. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Select.Group | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Select.GroupLabel | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Select.Separator | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `orientation` | `horizontal`, `vertical` | `horizontal` | The orientation of the separator. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Sheet URL: /docs/components/sheet Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/sheet/index.mdx Sheet는 화면의 가장자리에서 슬라이드되어 나타나는 오버레이 컴포넌트입니다. 사이드바, 메뉴, 폼, 상세 정보 등을 표시할 때 사용합니다. ```tsx 'use client'; import { Box, Button, Sheet } from '@vapor-ui/core'; import { CloseOutlineIcon } from '@vapor-ui/icons'; export default function DefaultSheet() { return ( }>Open Sheet 알림 Sheet는 화면 가장자리에서 슬라이드되어 나타나는 오버레이 컴포넌트입니다. 추가 정보나 작업을 위한 공간을 제공합니다. }>닫기 확인} /> ); } ``` ## Property *** ### Side Sheet가 나타날 위치를 설정합니다. 기본값은 'right'입니다. ```tsx 'use client'; import { Box, Button, HStack, Sheet, Text, VStack } from '@vapor-ui/core'; import { CloseOutlineIcon } from '@vapor-ui/icons'; export default function SheetSide() { return ( right }>Right 우측 Sheet 화면 우측에서 슬라이드됩니다. (기본값) left }>Left 좌측 Sheet 화면 좌측에서 슬라이드됩니다. top }>Top 상단 Sheet 화면 상단에서 슬라이드됩니다. bottom }>Bottom 하단 Sheet 화면 하단에서 슬라이드됩니다. ); } ``` ### Controlled State Sheet의 열림/닫힘 상태를 외부에서 제어합니다. ```tsx 'use client'; import { useEffect, useState } from 'react'; import { Box, Button, Sheet, Text, VStack } from '@vapor-ui/core'; import { CloseOutlineIcon } from '@vapor-ui/icons'; export default function SheetControlled() { const [isOpen, setIsOpen] = useState(false); const [count, setCount] = useState(3); useEffect(() => { let timer: NodeJS.Timeout; if (isOpen && count > 0) { timer = setTimeout(() => { setCount((prev) => prev - 1); }, 1000); } else if (isOpen && count === 0) { setIsOpen(false); setCount(3); // 초기화 } return () => { if (timer) clearTimeout(timer); }; }, [count, isOpen]); return ( 현재 상태: {isOpen ? '열림' : '닫힘'} 제어된 Sheet 외부에 의해{' '} {count} 초 후 상태가 제어됩니다.
프로그래밍 방식으로 열림/닫힘을 관리할 수 있습니다.
}>닫기
); } ```
### Keep Mounted Sheet가 닫혀도 DOM에서 제거되지 않고 유지되도록 설정합니다. ```tsx 'use client'; import { Box, Button, HStack, Sheet, Text, TextInput, VStack } from '@vapor-ui/core'; import { CloseOutlineIcon } from '@vapor-ui/icons'; export default function SheetKeepMounted() { return ( normal }>일반 Sheet 일반 Sheet 이 Sheet는 닫힐 때 DOM에서 제거됩니다. 다시 열 때마다 내용이 새로 생성됩니다. keepMounted }> 유지 Sheet 유지되는 Sheet 이 Sheet는 닫혀도 DOM에 유지됩니다. 입력한 내용이 보존되는 것을 확인해보세요. ); } ``` ## Examples *** ### Custom Usage 유연하게 Sheet를 사용합니다. ```tsx 'use client'; import { Box, Button, Sheet } from '@vapor-ui/core'; import { CloseOutlineIcon } from '@vapor-ui/icons'; export default function Flexible() { return ( }>유연한 Sheet 간단한 Sheet 이 Sheet는 Vapor UI의 Primitive 컴포넌트를 사용하여 유연하게 구성되었습니다. ); } ``` ### Resizable Sheet의 크기를 자유자재로 조절하길 원한다면 ``을 사용하세요. 조절 가능 영역을 제한하고 싶다면 `` 컴포넌트에 `min/max-height`, `min/max-width` 속성을 적용하세요. ```tsx 'use client'; import type { CSSProperties } from 'react'; import { Box, Button, HStack, Sheet, Text, VStack } from '@vapor-ui/core'; import { CloseOutlineIcon } from '@vapor-ui/icons'; type Side = 'right' | 'left' | 'top' | 'bottom'; type Case = { side: Side; label: string; description: string; /** Resize bounds live in CSS: min/max of the resized axis on the Popup. */ bounds: CSSProperties; }; const CASES: Case[] = [ { side: 'right', label: 'right', description: '우측 Sheet입니다. 왼쪽 가장자리 핸들을 잡고 좌우로 끌어 너비를 조절하세요.', bounds: { minWidth: 300, maxWidth: '80vw' }, }, { side: 'left', label: 'left', description: '좌측 Sheet입니다. 오른쪽 가장자리 핸들을 잡고 좌우로 끌어 너비를 조절하세요.', bounds: { minWidth: 300, maxWidth: '80vw' }, }, { side: 'top', label: 'top', description: '상단 Sheet입니다. 아래쪽 가장자리 핸들을 잡고 위아래로 끌어 높이를 조절하세요.', bounds: { height: 360, minHeight: 200, maxHeight: '80svh' }, }, { side: 'bottom', label: 'bottom', description: '하단 Sheet입니다. 위쪽 가장자리 핸들을 잡고 위아래로 끌어 높이를 조절하세요.', bounds: { height: 360, minHeight: 200, maxHeight: '80svh' }, }, ]; export default function ResizableSheet() { return ( {CASES.map(({ side, label, description, bounds }) => ( {label} }>{label} 크기 조절 가능한 Sheet ({label}) {description} ))} ); } ``` ## Props Table *** ### Sheet.Root | Prop | Type | Default | Description | | ---------------------- | --------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultOpen` | `boolean` | `false` | Whether the dialog is initially open.

To render a controlled dialog, use the `open` prop instead. | | `onOpenChange` | `function` | - | Event handler called when the dialog is opened or closed. | | `open` | `boolean` | - | Whether the dialog is currently open. | | `closeOnClickOverlay` | `boolean` | - | When `true`, clicking the overlay closes the dialog. | | `actionsRef` | `React.RefObject` | - | A ref to imperative actions.
- `unmount`: Manually unmounts the dialog.
Call this after any externally controlled closing animation finishes.
- `close`: Closes the dialog imperatively when called. | | `children` | `ReactNode`, `function` | - | The content of the dialog.
This can be a regular React node or a render function that receives the `payload` of the active trigger. | | `defaultTriggerId` | `string`, `null` | - | ID of the trigger that the dialog is associated with.
This is useful in conjunction with the `defaultOpen` prop to create an initially open dialog. | | `handle` | `DialogHandle` | - | A handle to associate the dialog with a trigger.
If specified, allows external triggers to control the dialog's open state.
Can be created with the Dialog.createHandle() method. | | `modal` | `boolean`, `trap-focus` | `true` | Determines if the dialog enters a modal state when open.
- `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled.
- `false`: user interaction with the rest of the document is allowed.
- `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled.

When `modal` is `true` or `'trap-focus'`, render `<Dialog.Close>` inside `<Dialog.Popup>` so
touch screen readers can escape the popup. | | `onOpenChangeComplete` | `function` | - | Event handler called after any animations complete when the dialog is opened or closed. | | `triggerId` | `string`, `null` | - | ID of the trigger that the dialog is associated with.
This is useful in conjunction with the `open` prop to create a controlled dialog.
There's no need to specify this prop when the dialog is uncontrolled (that is, when the `open` prop is not set). | ### Sheet.Trigger | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `handle` | `DialogHandle` | - | A handle to associate the trigger with a dialog.
Can be created with the Dialog.createHandle() method. | | `id` | `string` | - | ID of the trigger. In addition to being forwarded to the rendered element,
it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot `triggerId` prop). | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `payload` | `unknown` | - | A payload to pass to the dialog when it is opened. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.Popup | Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `overlayElement` | `ReactElement` | - | Replaces the default `Sheet.OverlayPrimitive`. Use to change the backdrop. | | `portalElement` | `ReactElement` | - | Replaces the default `Sheet.PortalPrimitive`. Use to change the portal container. | | `positionerElement` | `ReactElement` | - | Replaces the default `Sheet.PositionerPrimitive`. Use to change the side the sheet slides in from. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is opened.
By default, focus moves to the first tabbable element inside the popup, except when the dialog
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Sheet.PortalPrimitive | Prop | Type | Default | Description | | ------------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `container` | `HTMLElement`, `ShadowRoot`, `React.RefObject`, `null` | - | A parent element to render the portal element into. | | `keepMounted` | `boolean` | `false` | Whether to keep the portal mounted in the DOM while the popup is hidden. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Sheet.OverlayPrimitive | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `forceRender` | `boolean` | `false` | Whether the backdrop is forced to render even when nested. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Sheet.PopupPrimitive | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `finalFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is closed.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (trigger or previously focused element).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `initialFocus` | `boolean`, `React.RefObject`, `function` | - | Determines the element to focus when the dialog is opened.
By default, focus moves to the first tabbable element inside the popup, except when the dialog
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

- `false`: Do not move focus.
- `true`: Move focus based on the default behavior (first tabbable element or popup).
- `RefObject`: Move focus to the ref element.
- `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Sheet.PositionerPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `side` | `bottom`, `left`, `right`, `top` | `right` | Edge of the viewport the sheet slides in from. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.ResizeHandle | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `disabled` | `boolean` | `false` | Disables the handle, blocking drag and keyboard resizing. | | `step` | `number` | `16` | Distance the sheet resizes per arrow-key press, in pixels. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.Header | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.Body | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.Footer | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.Title | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.Description | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Sheet.Close | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Skeleton URL: /docs/components/skeleton Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/skeleton/index.mdx 콘텐츠가 로딩 중임을 나타내는 플레이스홀더 요소입니다. ```tsx import { Skeleton } from '@vapor-ui/core'; export default function DefaultSkeleton() { return ; } ``` ## Property *** ### Shape Skeleton의 모서리 둥글기를 설정합니다. ```tsx import { HStack, Skeleton, Text, VStack } from '@vapor-ui/core'; export default function SkeletonShape() { return ( rounded square ); } ``` ### Animation Skeleton의 애니메이션 스타일을 설정합니다. ```tsx import { HStack, Skeleton, Text, VStack } from '@vapor-ui/core'; export default function SkeletonAnimation() { return ( shimmer pulse none ); } ``` ### Size Skeleton의 높이를 설정합니다. ```tsx import { HStack, Skeleton, Text, VStack } from '@vapor-ui/core'; export default function SkeletonSize() { return ( sm md lg xl ); } ``` ## Examples *** ### Profile Card 여러 Skeleton 요소를 조합하여 프로필 카드 플레이스홀더를 구성하는 예제입니다. ```tsx import { Box, HStack, Skeleton, VStack } from '@vapor-ui/core'; export default function SkeletonComposition() { return ( ); } ``` ## Props Table *** ### Skeleton | Prop | Type | Default | Description | | ----------- | --------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `animation` | `none`, `shimmer`, `pulse` | `shimmer` | Animation that shows the skeleton is loading. | | `shape` | `square`, `rounded` | `rounded` | Corner style of the skeleton. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the skeleton, controlling height. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Spinner URL: /docs/components/spinner Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/spinner/index.mdx 콘텐츠나 데이터 로딩 시 대기 상태를 표시합니다. ```tsx import { Spinner } from '@vapor-ui/core'; export default function DefaultSpinner() { return ; } ``` ## Property *** ### Size Spinner의 크기를 설정합니다. ```tsx import { HStack, Spinner, VStack } from '@vapor-ui/core'; export default function SpinnerSize() { return ( md lg xl ); } ``` ### Color Palette Spinner의 색상을 설정합니다. 다른 요소와 함께 사용될 때, `inherit` 속성을 사용하여 요소의 글자색과 통일하세요. ```tsx import { Button, HStack, Spinner } from '@vapor-ui/core'; export default function SpinnerColor() { return ( ); } ``` ## Props Table *** ### Spinner | Prop | Type | Default | Description | | -------------- | --------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `colorPalette` | `inherit`, `primary` | `primary` | Color palette of the spinner, applied to the stroke of the spinning arc. Use `inherit` to take the stroke color from the parent element's `color`, such as on a filled background. | | `size` | `md`, `lg`, `xl` | `md` | Size of the spinner, controlling width, height, and stroke width. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Switch URL: /docs/components/switch Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/switch/index.mdx Switch는 사용자가 설정을 on/off로 전환할 수 있게 돕는 토글 컴포넌트입니다. ```tsx import { Switch } from '@vapor-ui/core'; export default function DefaultSwitch() { return ; } ``` ## Property *** ### Size Switch의 크기를 설정합니다. ```tsx import { HStack, Switch, Text, VStack } from '@vapor-ui/core'; export default function SwitchSize() { return ( sm md lg ); } ``` ### Checked Switch의 체크 상태를 설정합니다. ```tsx import { HStack, Switch, Text, VStack } from '@vapor-ui/core'; export default function SwitchChecked() { return ( unchecked checked ); } ``` ### Disabled Switch의 비활성화 상태를 설정합니다. ```tsx import { HStack, Switch, Text, VStack } from '@vapor-ui/core'; export default function SwitchDisabled() { return ( unchecked checked ); } ``` ### Read Only 사용자는 스위치 상태를 변경할 수 없지만, 현재 상태를 확인할 수 있도록 허용하는 상태입니다. ```tsx import { HStack, Switch, Text, VStack } from '@vapor-ui/core'; export default function SwitchReadOnly() { return ( checked unchecked ); } ``` ## Examples *** ### Controlled 제어되는 Switch 컴포넌트의 사용 예시입니다. ```tsx 'use client'; import { useState } from 'react'; import { HStack, Switch, Text, VStack } from '@vapor-ui/core'; export default function SwitchControlled() { const [checked, setChecked] = useState(false); return ( State: {checked ? 'On' : 'Off'} ); } ``` ### Custom Thumb `children`으로 `Switch.ThumbPrimitive`를 전달하면 내부 파트를 직접 제어할 수 있습니다. 아이콘을 삽입하거나 다른 요소로 교체할 수 있습니다. ```tsx import { Switch } from '@vapor-ui/core'; import { HeartIcon } from '@vapor-ui/icons'; export default function SwitchCustomThumb() { return ( ); } ``` ## Props Table *** ### Switch.Root | Prop | Type | Default | Description | | ----------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid` | `boolean` | `false` | Marks the switch as invalid, applying error styles. Sets `aria-invalid` on the `<span>` element. | | `size` | `sm`, `md`, `lg` | `md` | Size of the switch, controlling its width, height, and padding, and the size of its thumb. | | `checked` | `boolean` | - | Whether the switch is currently active.

To render an uncontrolled switch, use the `defaultChecked` prop instead. | | `defaultChecked` | `boolean` | `false` | Whether the switch is initially active.

To render a controlled switch, use the `checked` prop instead. | | `onCheckedChange` | `function` | - | Event handler called when the switch is activated or deactivated. | | `value` | `string` | - | The value submitted with the form when the switch is on.
By default, switch submits the "on" value, matching native checkbox behavior. | | `children` | `ReactNode` | - | Element shown inside the switch in place of the default `Switch.ThumbPrimitive`, such as a `Switch.ThumbPrimitive` with custom props. Anything other than a single element is ignored and the default thumb is shown. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. | | `form` | `string` | - | Identifies the form that owns the hidden input.
Useful when the switch is rendered outside the form. | | `id` | `string` | - | The id of the hidden input element.

When `nativeButton` is `true`, the id is applied to the root element. | | `inputRef` | `React.Ref` | - | A ref to access the hidden `<input>` element. | | `name` | `string` | - | Identifies the field when a form is submitted. | | `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `true` if the rendered element is a native button. | | `readOnly` | `boolean` | `false` | Whether the user should be unable to activate or deactivate the switch. | | `required` | `boolean` | `false` | Whether the user must activate the switch before submitting a form. | | `uncheckedValue` | `string` | - | The value submitted with the form when the switch is off.
By default, unchecked switches do not submit any value, matching native checkbox behavior. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Switch.ThumbPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Table URL: /docs/components/table Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/table/index.mdx Table는 데이터를 행과 열로 구성하여 구조화된 방식으로 표시하는 컴포넌트입니다. Table 컴포넌트는 순수한 뷰(View) 역할에 집중하여 기본적인 구조와 스타일만을 제공합니다. 복잡한 상태 관리와 로직을 바탕으로 대량의 데이터를 다루는 Data Table을 구현하려면 [Table Block 문서](/docs/components/patterns/table)를 참고해주세요.
```tsx import { Badge, Table } from '@vapor-ui/core'; const datas = [ { name: 'Olivia Park', status: 'active', role: 'designer', 'last-active': '2 hours ago' }, { name: 'Ethan Kim', status: 'active', role: 'developer', 'last-active': '3 days ago' }, { name: 'Mia Choi', status: 'inactive', role: 'developer', 'last-active': '10 minutes ago' }, { name: 'Noah Lee', status: 'active', role: 'designer', 'last-active': '1 day ago' }, { name: 'Ava Jung', status: 'active', role: 'developer', 'last-active': '5 days ago' }, { name: 'Liam Han', status: 'inactive', role: 'developer', 'last-active': '5 days ago' }, { name: 'Emma Seo', status: 'active', role: 'designer', 'last-active': '7 days ago' }, { name: 'Mason Yoo', status: 'active', role: 'designer', 'last-active': '30 minutes ago' }, { name: 'Sophia Lim', status: 'inactive', role: 'designer', 'last-active': '4 hours ago' }, { name: 'Lucas Park', status: 'active', role: 'developer', 'last-active': '1 hour ago' }, ]; const activeness: Record = { active: 'success', inactive: 'hint', }; export default function Basic() { return ( Name Status Role Last Active {datas.map((data, index) => ( {data.name} {data.status.toUpperCase()} {data.role} {data['last-active']} ))} ); } ``` ## Props Table *** ### Table.Root | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.Header | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.Body | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.Footer | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.Row | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.Heading | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.Cell | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.ColumnGroup | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Table.Column | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Tabs URL: /docs/components/tabs Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/tabs/index.mdx Tabs는 관련된 콘텐츠를 탭 형태로 구성하여 사용자가 쉽게 전환할 수 있도록 하는 컴포넌트입니다. 키보드 내비게이션, 접근성, 다양한 스타일 변형을 지원합니다. ```tsx import { Tabs } from '@vapor-ui/core'; import { AiSmartieIcon, AssignmentIcon, ListIcon } from '@vapor-ui/icons'; export default function DefaultTabs() { return ( 개요 기능 예시 ); } ``` ## Property *** ### Size Tabs의 크기를 지정합니다. `sm`, `md`, `lg`, `xl` 네 가지 크기를 제공합니다. ```tsx import { HStack, Tabs, Text, VStack } from '@vapor-ui/core'; export default function TabsSize() { return ( sm Tab 1 Tab 2 Tab 3 md Tab 1 Tab 2 Tab 3 lg Tab 1 Tab 2 Tab 3 xl Tab 1 Tab 2 Tab 3 ); } ``` ### Variant Tabs의 스타일 변형을 설정합니다. `line`과 `fill` 두 가지 스타일을 제공합니다. ```tsx import { HStack, Tabs, Text, VStack } from '@vapor-ui/core'; export default function TabsVariant() { return ( line Home About Services fill Home About Services ); } ``` ### Orientation 수평(horizontal)과 수직(vertical) 방향을 설정합니다. ```tsx import { HStack, Tabs, Text, VStack } from '@vapor-ui/core'; export default function TabsOrientation() { return ( horizontal Tab 1 Tab 2 Tab 3 vertical Tab 1 Tab 2 Tab 3 ); } ``` ### Controlled State Tabs의 활성 상태를 외부에서 제어합니다. ```tsx 'use client'; import { useState } from 'react'; import { Button, Tabs, VStack } from '@vapor-ui/core'; export default function TabsControlled() { const [activeTab, setActiveTab] = useState('profile'); return ( 프로필 계정 보안 알림
현재 선택된 탭: {activeTab}
); } ```
### States 개별 탭 또는 전체 탭 그룹을 비활성화할 수 있습니다. ```tsx import { HStack, Tabs, Text, VStack } from '@vapor-ui/core'; export default function TabsStates() { return ( tab disabled Enabled Disabled Normal group disabled Enabled Disabled Normal ); } ``` ## Examples *** ### Keyboard Navigation `activateOnFocus`와 `loopFocus` props를 사용하여 키보드 내비게이션 동작을 세밀하게 제어할 수 있습니다. ```tsx import { Tabs, VStack } from '@vapor-ui/core'; export default function TabsKeyboard() { return (

포커스 시 활성화 (activateOnFocus: true)

탭 1 탭 2 탭 3

엔터/스페이스로 활성화 (activateOnFocus: false)

탭 1 탭 2 탭 3

비순환 내비게이션 (loopFocus: false)

탭 1 탭 2 탭 3
); } ```
### Custom Indicator `Tabs.ListPrimitive`와 `Tabs.IndicatorPrimitive`를 직접 조합하면 인디케이터의 스타일을 제어할 수 있습니다. ```tsx import { Tabs } from '@vapor-ui/core'; export default function TabsCustomIndicator() { return ( 홈 소개 서비스 ); } ``` ## Props Table *** ### Tabs.Root | Prop | Type | Default | Description | | ----------------- | --------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the tab buttons, controlling height and typography. | | `variant` | `line`, `fill` | `line` | Visual style of the tabs. `line` marks the active tab with a line on the border of the list, `fill` highlights the active tab with a filled background. | | `defaultValue` | `any` | `0` | The default value. Use when the component is not controlled.
When the value is `null`, no Tab will be active. | | `onValueChange` | `function` | - | Callback invoked when new value is being set.

The event `reason` is `'none'` for user-initiated changes, such as a click
or keyboard navigation; `'initial'` for the first automatic selection or
fallback in uncontrolled roots when `defaultValue` is omitted or
`undefined`, including when the implicit initial value is disabled or
missing; `'disabled'` for automatic fallback when the selected tab becomes
disabled in uncontrolled roots; or `'missing'` for automatic fallback when
the selected tab is removed, or when an explicit `defaultValue` never
matches a mounted tab in uncontrolled roots.

For automatic changes, the selected value can be `null` when no enabled Tab
is available as a fallback.

Automatic changes cannot be canceled; calling `eventDetails.cancel()` for
`'initial'`, `'disabled'`, or `'missing'` has no effect. | | `value` | `any` | - | The value of the currently active `Tab`. Use when the component is controlled.
When the value is `null`, no Tab will be active. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `disabled` | `boolean` | - | Disables every tab button, blocking all interactions. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `activateOnFocus` | `boolean` | `false` | Whether to automatically change the active tab on arrow key focus.
Otherwise, tabs will be activated using \Enter\ or \Space\ key press. | | `loopFocus` | `boolean` | `true` | Whether to loop keyboard focus back to the first item
when the end of the list is reached while using the arrow keys. | | `orientation` | `horizontal`, `vertical` | `horizontal` | The component orientation (layout flow direction). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Tabs.List | Prop | Type | Default | Description | | ------------------ | -------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `indicatorElement` | `ReactElement` | - | Replaces the default `Tabs.IndicatorPrimitive`. Use to change how the active tab is highlighted. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Tabs.ListPrimitive | Prop | Type | Default | Description | | ----------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | #### Tabs.IndicatorPrimitive | Prop | Type | Default | Description | | ----------------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `renderBeforeHydration` | `boolean` | `false` | Whether to render itself before React hydrates.
This minimizes the time that the indicator isn't visible after server-side rendering. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Tabs.Button | Prop | Type | Default | Description | | -------------- | --------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `any` | - | The value of the Tab. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `disabled` | `boolean` | - | Whether the Tab is disabled.

If a first Tab on a `<Tabs.List>` is disabled, it won't initially be selected.
Instead, the next enabled Tab will be selected.
However, it does not work like this during server-side rendering, as it is not known
during pre-rendering which Tabs are disabled.
To work around it, ensure that `defaultValue` or `value` on `<Tabs.Root>` is set to an enabled Tab's value. | | `nativeButton` | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`). | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | ### Tabs.Panel | Prop | Type | Default | Description | | ------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **value** | `any` | - | The value of the TabPanel. It will be shown when the Tab with the corresponding value is active. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `keepMounted` | `boolean` | `false` | Whether to keep the HTML element in the DOM while the panel is hidden. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Text URL: /docs/components/text Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/text/index.mdx Text 컴포넌트는 시멘틱 태그와 타이포그래피·색상 토큰을 조합하여 텍스트 스타일을 설정합니다. ```tsx import { Text } from '@vapor-ui/core'; export default function DefaultText() { return Hello World; } ``` ## Property *** ### Typography 텍스트의 타이포그래피 스타일을 설정합니다. ```tsx import { Text, VStack } from '@vapor-ui/core'; export default function TextTypography() { return ( Display1 Heading1 Subtitle1 Body1 ); } ``` ### Foreground 텍스트의 색상을 설정합니다. ```tsx import { HStack, Text } from '@vapor-ui/core'; export default function TextForeground() { return ( Primary Secondary Success Warning Danger Hint ); } ``` ## Props Table *** ### Text | Prop | Type | Default | Description | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `foreground` | `hint`, `normal`, `white`, `primary-100`, `primary-200`, `primary`, `secondary-100`, `secondary-200`, `secondary`, `success-100`, `success-200`, `success`, `warning-100`, `warning-200`, `warning`, `danger-100`, `danger-200`, `danger`, `hint-100`, `hint-200`, `contrast-100`, `contrast-200`, `contrast`, `primary-strong`, `success-strong`, `warning-strong`, `danger-strong`, `normal-100`, `normal-200`, `inverse`, `staticWhite`, `staticBlack` | `normal` | Color of the text, chosen from the foreground color palette. | | `typography` | `body1`, `display1`, `display2`, `display3`, `display4`, `heading1`, `heading2`, `heading3`, `heading4`, `heading5`, `heading6`, `subtitle1`, `subtitle2`, `body2`, `body3`, `body4`, `code1`, `code2` | `body1` | Typography style of the text, setting font size, line height, font weight, and letter spacing. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # TextInput URL: /docs/components/text-input Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/text-input/index.mdx TextInput은 사용자가 데이터를 입력할 수 있도록 텍스트, 숫자 등 다양한 형식의 입력 필드를 제공합니다. ```tsx import { TextInput } from '@vapor-ui/core'; export default function DefaultTextInput() { return ; } ``` ## Property *** ### Size TextInput의 크기를 설정합니다. ```tsx import { HStack, Text, TextInput, VStack } from '@vapor-ui/core'; export default function TextInputSize() { return ( sm md lg xl ); } ``` ### Type TextInput의 타입을 설정합니다. ```tsx import { HStack, Text, TextInput, VStack } from '@vapor-ui/core'; export default function TextInputType() { return ( text email password ); } ``` ### Disabled 사용자가 상호작용할 수 없는 상태입니다. 액션을 수행하기 위한 특정 조건을 충족하지 않았거나 일시적으로 기능을 제한하려는 상황에서 사용합니다. ```tsx import { TextInput, VStack } from '@vapor-ui/core'; export default function TextInputDisabled() { return ( ); } ``` ### Invalid 유효하지 않은 상태(필수 항목 누락, 잘못된 입력 등)를 표시하여 올바른 입력을 유도합니다. ```tsx import { TextInput, VStack } from '@vapor-ui/core'; export default function TextInputInvalid() { return ( ); } ``` ### Read Only 값을 수정할 수 없지만, 텍스트를 복사하거나 읽을 수 있는 상태입니다. ```tsx import { TextInput, VStack } from '@vapor-ui/core'; export default function TextInputReadOnly() { return ( ); } ``` ## Examples *** ### States TextInput의 다양한 상태를 보여줍니다. ```tsx import { HStack, Text, TextInput, VStack } from '@vapor-ui/core'; export default function TextInputStates() { return ( default disabled invalid readOnly ); } ``` ## Props Table *** ### TextInput | Prop | Type | Default | Description | | --------------- | --------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid` | `boolean` | `false` | Marks the text input as invalid, applying error styles. Sets `aria-invalid` on the `<input>` element. | | `size` | `sm`, `md`, `lg`, `xl` | `md` | Size of the text input, controlling height, padding, and typography. | | `defaultValue` | `string` | \`\` | Initial text in the field. Use when uncontrolled. | | `onValueChange` | `function` | - | Called when the text changes as the user types, pastes, or deletes. Receives the new text and the change event details. | | `value` | `string` | - | Current text in the field. Use when controlled. | | `className` | `string`, `function` | - | CSS class applied to the element, or a function that
returns a class based on the component's state. | | `style` | `React.CSSProperties`, `function` | - | Style applied to the element, or a function that
returns a style object based on the component's state. | | `type` | `search`, `text`, `tel`, `url`, `email`, `password` | - | Kind of text the field accepts, such as an email address, password, or URL. | | `render` | `ReactElement`, `function` | - | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render. | # Textarea URL: /docs/components/textarea Source: https://raw.githubusercontent.com/goorm-dev/vapor-ui/refs/heads/main/apps/website/content/docs/components/(components)/textarea/index.mdx Textarea는 사용자가 여러 줄의 텍스트를 입력할 수 있도록 하는 텍스트 입력 필드를 제공합니다. ```tsx import { Box, Textarea } from '@vapor-ui/core'; export default function DefaultTextarea() { return (