Select
Select는 사용자가 여러 옵션 중에서 하나를 선택할 수 있는 드롭다운 컴포넌트입니다. 폼 입력, 설정 선택, 필터링 등에 사용되며, 키보드 내비게이션과 접근성을 완벽하게 지원합니다.import { Select } from '@vapor-ui/core';
export default function DefaultSelect() {
return (
<Select.Root placeholder="폰트를 선택하세요">
<Select.Trigger width="400px" />
<Select.Popup>
<Select.Group>
<Select.GroupLabel>폰트</Select.GroupLabel>
<Select.Item value="sans-serif">Sans-serif</Select.Item>
<Select.Item value="serif">Serif</Select.Item>
<Select.Item value="mono">Monospace</Select.Item>
<Select.Item value="cursive">Cursive</Select.Item>
</Select.Group>
</Select.Popup>
</Select.Root>
);
}Property
Size
Select의 크기를 설정합니다.
import { Flex, Select } from '@vapor-ui/core';
export default function SelectSize() {
return (
<Flex maxWidth="800px" width="100%" gap="$250">
<SelectTemplate placeholder="Small" size="sm" />
<SelectTemplate placeholder="Medium" size="md" />
<SelectTemplate placeholder="Large" size="lg" />
<SelectTemplate placeholder="Extra Large" size="xl" />
</Flex>
);
}
const SelectTemplate = (props: Select.Root.Props) => {
return (
<Select.Root {...props}>
<Select.Trigger />
<Select.Popup>
<Select.Item value="option1">옵션 1</Select.Item>
<Select.Item value="option2">옵션 2</Select.Item>
</Select.Popup>
</Select.Root>
);
};Positioning
Select 드롭다운이 나타날 위치를 설정합니다. 기본값은 'bottom'입니다.
import { HStack, Select } from '@vapor-ui/core';
export default function SelectPositioning() {
return (
<HStack maxWidth="800px" width="100%" gap="$250">
<Select.Root placeholder="Top">
<Select.Trigger />
<Select.Popup positionerElement={<Select.PositionerPrimitive side="top" />}>
<Select.Item value="option1">옵션 1</Select.Item>
<Select.Item value="option2">옵션 2</Select.Item>
</Select.Popup>
</Select.Root>
<Select.Root placeholder="Right">
<Select.Trigger />
<Select.Popup positionerElement={<Select.PositionerPrimitive side="right" />}>
<Select.Item value="option1">옵션 1</Select.Item>
<Select.Item value="option2">옵션 2</Select.Item>
</Select.Popup>
</Select.Root>
<Select.Root placeholder="Bottom">
<Select.Trigger />
<Select.Popup positionerElement={<Select.PositionerPrimitive side="bottom" />}>
<Select.Item value="option1">옵션 1</Select.Item>
<Select.Item value="option2">옵션 2</Select.Item>
</Select.Popup>
</Select.Root>
<Select.Root placeholder="Left">
<Select.Trigger />
<Select.Popup positionerElement={<Select.PositionerPrimitive side="left" />}>
<Select.Item value="option1">옵션 1</Select.Item>
<Select.Item value="option2">옵션 2</Select.Item>
</Select.Popup>
</Select.Root>
</HStack>
);
}Controlled State
Select의 선택 상태를 외부에서 제어합니다.
'use client';
import { useState } from 'react';
import { Button, HStack, Select, Text } from '@vapor-ui/core';
export default function SelectControlled() {
const [value, setValue] = useState<string>('');
const handleValueChange = (newValue: unknown) => {
setValue(newValue as string);
};
return (
<div className="space-y-4">
<Select.Root placeholder="폰트 선택" value={value} onValueChange={handleValueChange}>
<Select.Trigger />
<Select.Popup>
<Select.Group>
<Select.GroupLabel>폰트</Select.GroupLabel>
<Select.Item value="sans">Sans-serif</Select.Item>
<Select.Item value="serif">Serif</Select.Item>
<Select.Item value="mono">Monospace</Select.Item>
<Select.Item value="cursive">Cursive</Select.Item>
</Select.Group>
</Select.Popup>
</Select.Root>
<Text typography="body2" foreground="secondary-200">
선택된 값: <code className="bg-gray-100 px-1 rounded">{value || '없음'}</code>
</Text>
<HStack gap="$100">
<Button colorPalette="primary" onClick={() => setValue('serif')}>
Serif 선택
</Button>
<Button onClick={() => setValue('')} colorPalette="secondary">
선택 해제
</Button>
</HStack>
</div>
);
}States
Select의 다양한 상태(비활성화, 읽기 전용, 오류)를 설정합니다.
import { Select, VStack } from '@vapor-ui/core';
export default function SelectStates() {
return (
<VStack gap="$200" width="400px" className="flex-wrap">
<SelectTemplate placeholder="기본 상태" />
<SelectTemplate placeholder="비활성화" disabled />
<SelectTemplate placeholder="읽기 전용" readOnly />
<SelectTemplate placeholder="오류 상태" invalid />
</VStack>
);
}
const SelectTemplate = (props: Select.Root.Props) => {
return (
<Select.Root {...props}>
<Select.Trigger />
<Select.Popup>
<Select.Item value="option1">옵션 1</Select.Item>
<Select.Item value="option2">옵션 2</Select.Item>
</Select.Popup>
</Select.Root>
);
};Examples
Items Configuration
배열 형태와 객체 형태의 아이템 데이터를 모두 지원합니다.
import { Select, 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 (
<VStack gap="$300" width="400px">
<VStack>
<h4 className="text-sm font-medium mb-2">배열 형태의 아이템</h4>
<Select.Root placeholder="폰트 선택" items={fonts}>
<Select.Trigger />
<Select.Popup>
<Select.Group>
<Select.GroupLabel>폰트</Select.GroupLabel>
{fonts.map((font) => (
<Select.Item key={font.value} value={font.value}>
{font.label}
</Select.Item>
))}
</Select.Group>
</Select.Popup>
</Select.Root>
</VStack>
<VStack>
<h4 className="text-sm font-medium mb-2">객체 형태의 아이템</h4>
<Select.Root placeholder="언어 선택" items={languages}>
<Select.Trigger />
<Select.Popup>
<Select.Group>
<Select.GroupLabel>프로그래밍 언어</Select.GroupLabel>
{Object.entries(languages).map(([value, label]) => (
<Select.Item key={value} value={value}>
{label}
</Select.Item>
))}
</Select.Group>
</Select.Popup>
</Select.Root>
</VStack>
</VStack>
);
}Grouping Options
관련된 옵션들을 그룹으로 묶어 구조화할 수 있습니다. Group과 GroupLabel, Separator를 사용하여 명확한 구조를 만들 수 있습니다.
import { Select, VStack } from '@vapor-ui/core';
export default function SelectGrouping() {
return (
<VStack width="400px">
<Select.Root placeholder="개발 도구 선택">
<Select.Trigger />
<Select.Popup>
<Select.Group>
<Select.GroupLabel>프론트엔드</Select.GroupLabel>
<Select.Item value="react">React</Select.Item>
<Select.Item value="vue">Vue</Select.Item>
<Select.Item value="angular">Angular</Select.Item>
</Select.Group>
<Select.Separator />
<Select.Group>
<Select.GroupLabel>백엔드</Select.GroupLabel>
<Select.Item value="nodejs">Node.js</Select.Item>
<Select.Item value="python">Python</Select.Item>
<Select.Item value="java">Java</Select.Item>
</Select.Group>
<Select.Separator />
<Select.Group>
<Select.GroupLabel>데이터베이스</Select.GroupLabel>
<Select.Item value="mysql">MySQL</Select.Item>
<Select.Item value="postgresql">PostgreSQL</Select.Item>
<Select.Item value="mongodb">MongoDB</Select.Item>
</Select.Group>
</Select.Popup>
</Select.Root>
</VStack>
);
}Custom Value Display
Select.Value에 함수형 children을 제공하여 선택된 값을 커스터마이징할 수 있습니다.
import { Box, Select } from '@vapor-ui/core';
const fonts = {
sans: 'Sans-serif',
serif: 'Serif',
mono: 'Monospace',
cursive: 'Cursive',
};
const renderValue = (value: string) => {
if (!value) return '선택된 폰트 없음';
return <span style={{ fontFamily: value }}>{fonts[value as keyof typeof fonts]}</span>;
};
export default function SelectCustomValue() {
return (
<Box width="400px">
<Select.Root placeholder="폰트 선택" items={fonts}>
<h4 className="text-sm font-medium mb-2">커스텀 값 표시</h4>
<Select.Trigger>
<Select.ValuePrimitive>{renderValue}</Select.ValuePrimitive>
<Select.TriggerIconPrimitive />
</Select.Trigger>
<Select.Popup>
{Object.entries(fonts).map(([value, label]) => (
<Select.Item key={value} value={value}>
<span style={{ fontFamily: value }}>{label}</span>
</Select.Item>
))}
</Select.Popup>
</Select.Root>
</Box>
);
}Props Table
Select.Root
Loading component documentation...
Select.Trigger
Loading component documentation...
Select.ValuePrimitive
Loading component documentation...
Select.PlaceholderPrimitive
Loading component documentation...
Select.TriggerIconPrimitive
Loading component documentation...
Select.Popup
Loading component documentation...
Select.PositionerPrimitive
Loading component documentation...
Select.PopupPrimitive
Loading component documentation...
Select.Item
Loading component documentation...
Select.ItemPrimitive
Loading component documentation...
Select.ItemIndicatorPrimitive
Loading component documentation...
Select.Group
Loading component documentation...
Select.GroupLabel
Loading component documentation...
Select.Separator
Loading component documentation...