CoreMultiSelectPrim
레거시 compound MultiSelect 컴포넌트. 다중 값 선택을 지원하며 신규 프로젝트에서는 Select(multiple)로 전환을 권장합니다.
개요
마이그레이션 안내 — 이 컴포넌트는 레거시입니다. 신규 프로젝트에서는
Select의 multiple 모드를 사용하세요.
MultiSelectPrim은 Radix UI Select를 기반으로 다중 선택을 지원하는 compound 컴포넌트입니다.
- 다중 값 관리 —
value가string[]이며 선택/해제를 직접 핸들링해야 합니다 - CoreTag 기본 표시 — 선택된 값은 기본적으로
CoreTag목록으로 Trigger에 렌더됩니다 - 함수형 children —
Item에서(selected: boolean) => ReactNode패턴으로CoreCheckbox등과 조합 가능 - 커스텀 Value —
Value의children을 함수(selectedList) => ReactNode로 작성해 커스텀 렌더 지원 valueWrap— 선택 값이 많을 때 Trigger 높이를 늘려 줄바꿈으로 표시하는 옵션
Usage
기본 사용법
() => { const [selected, setSelected] = React.useState([]); const toggle = (value) => setSelected((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value] ); return ( <CoreMultiSelectPrim.Root value={selected} onValueChange={toggle} required width="240px"> <CoreMultiSelectPrim.Label tooltip="도움말">Label</CoreMultiSelectPrim.Label> <CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Value placeholder="옵션을 선택하세요" /> </CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.HelperText>Helper Text</CoreMultiSelectPrim.HelperText> <CoreMultiSelectPrim.Portal> <CoreMultiSelectPrim.Content> <CoreMultiSelectPrim.Item value="option1"> {(sel) => <CoreCheckbox checked={sel} label="Option 1" onChange={() => {}} />} </CoreMultiSelectPrim.Item> <CoreMultiSelectPrim.Item value="option2"> {(sel) => <CoreCheckbox checked={sel} label="Option 2" onChange={() => {}} />} </CoreMultiSelectPrim.Item> <CoreMultiSelectPrim.Item value="option3" disabled> {(sel) => <CoreCheckbox checked={sel} label="Option 3 (disabled)" onChange={() => {}} />} </CoreMultiSelectPrim.Item> </CoreMultiSelectPrim.Content> </CoreMultiSelectPrim.Portal> </CoreMultiSelectPrim.Root> ); }
Controlled
() => { const [selected, setSelected] = React.useState(['option1', 'option2']); const toggle = (value) => setSelected((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value] ); return ( <CoreMultiSelectPrim.Root value={selected} onValueChange={toggle} required width="240px"> <CoreMultiSelectPrim.Label>Label</CoreMultiSelectPrim.Label> <CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Value /> </CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Portal> <CoreMultiSelectPrim.Content> <CoreMultiSelectPrim.Item value="option1"> {(sel) => <CoreCheckbox checked={sel} label="Option 1" onChange={() => {}} />} </CoreMultiSelectPrim.Item> <CoreMultiSelectPrim.Item value="option2"> {(sel) => <CoreCheckbox checked={sel} label="Option 2" onChange={() => {}} />} </CoreMultiSelectPrim.Item> </CoreMultiSelectPrim.Content> </CoreMultiSelectPrim.Portal> </CoreMultiSelectPrim.Root> ); }
valueWrap으로 줄바꿈 표시
선택 항목이 많을 때 valueWrap을 켜면 Trigger가 높이를 늘려 모든 태그를 표시합니다.
() => { const items = ['option1', 'option2', 'option3', 'option4', 'option5']; const [selected, setSelected] = React.useState(items); const toggle = (value) => setSelected((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value] ); return ( <CoreMultiSelectPrim.Root value={selected} onValueChange={toggle} required width="300px"> <CoreMultiSelectPrim.Label>Label</CoreMultiSelectPrim.Label> <CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Value valueWrap /> </CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Portal> <CoreMultiSelectPrim.Content> {items.map((v) => ( <CoreMultiSelectPrim.Item key={v} value={v}> {(sel) => <CoreCheckbox checked={sel} label={v} onChange={() => {}} />} </CoreMultiSelectPrim.Item> ))} </CoreMultiSelectPrim.Content> </CoreMultiSelectPrim.Portal> </CoreMultiSelectPrim.Root> ); }
그룹과 구분선
() => { const [selected, setSelected] = React.useState([]); const toggle = (value) => setSelected((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value] ); return ( <CoreMultiSelectPrim.Root value={selected} onValueChange={toggle} required width="240px"> <CoreMultiSelectPrim.Label>Label</CoreMultiSelectPrim.Label> <CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Value /> </CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Portal> <CoreMultiSelectPrim.Content> <CoreMultiSelectPrim.Group> <CoreMultiSelectPrim.GroupLabel>그룹 1</CoreMultiSelectPrim.GroupLabel> <CoreMultiSelectPrim.Item value="option1"> {(sel) => <CoreCheckbox checked={sel} label="Option 1" onChange={() => {}} />} </CoreMultiSelectPrim.Item> <CoreMultiSelectPrim.Item value="option2"> {(sel) => <CoreCheckbox checked={sel} label="Option 2" onChange={() => {}} />} </CoreMultiSelectPrim.Item> </CoreMultiSelectPrim.Group> <CoreMultiSelectPrim.Separator /> <CoreMultiSelectPrim.Group> <CoreMultiSelectPrim.GroupLabel>그룹 2</CoreMultiSelectPrim.GroupLabel> <CoreMultiSelectPrim.Item value="option3" label="Option 3"> {(sel) => <CoreCheckbox checked={sel} label="Option 3" onChange={() => {}} />} </CoreMultiSelectPrim.Item> </CoreMultiSelectPrim.Group> </CoreMultiSelectPrim.Content> </CoreMultiSelectPrim.Portal> </CoreMultiSelectPrim.Root> ); }
label prop으로 Trigger 표시 텍스트 분리
Item의 children과 Trigger에 표시되는 텍스트를 다르게 하려면 label prop을 사용합니다.
() => { const [selected, setSelected] = React.useState([]); const toggle = (value) => setSelected((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value] ); return ( <CoreMultiSelectPrim.Root value={selected} onValueChange={toggle} required width="240px"> <CoreMultiSelectPrim.Label>Label</CoreMultiSelectPrim.Label> <CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Value /> </CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Portal> <CoreMultiSelectPrim.Content> <CoreMultiSelectPrim.Item value="option1" label="Option 1"> {(sel) => <CoreCheckbox checked={sel} label="커스텀 표시 텍스트" onChange={() => {}} />} </CoreMultiSelectPrim.Item> <CoreMultiSelectPrim.Item value="option2" label="Option 2"> {(sel) => <CoreCheckbox checked={sel} label="다른 커스텀 텍스트" onChange={() => {}} />} </CoreMultiSelectPrim.Item> </CoreMultiSelectPrim.Content> </CoreMultiSelectPrim.Portal> </CoreMultiSelectPrim.Root> ); }
커스텀 Value 렌더
Value의 children을 (selectedList) => ReactNode 함수로 작성하면 선택 목록 전체를 받아 자유롭게 렌더할 수 있습니다.
() => { const options = { option1: 'Option 1', option2: 'Option 2', option3: 'Option 3' }; const [selected, setSelected] = React.useState([]); const toggle = (value) => setSelected((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value] ); return ( <CoreMultiSelectPrim.Root value={selected} onValueChange={toggle} required width="240px"> <CoreMultiSelectPrim.Label>Label</CoreMultiSelectPrim.Label> <CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Value> {(list) => ( <div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap' }}> {list.map(({ value, label }) => ( <CoreStatusBadge key={value} text={label} type="tint" /> ))} </div> )} </CoreMultiSelectPrim.Value> </CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Portal> <CoreMultiSelectPrim.Content> {Object.entries(options).map(([value, label]) => ( <CoreMultiSelectPrim.Item key={value} value={value} label={label}> {(sel) => <CoreCheckbox checked={sel} label={label} onChange={() => {}} />} </CoreMultiSelectPrim.Item> ))} </CoreMultiSelectPrim.Content> </CoreMultiSelectPrim.Portal> </CoreMultiSelectPrim.Root> ); }
상태(status)와 크기(size)
() => { const [selected, setSelected] = React.useState([]); const toggle = (value) => setSelected((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value] ); return ( <CoreMultiSelectPrim.Root value={selected} onValueChange={toggle} status="error" size="lg" width="300px" required > <CoreMultiSelectPrim.Label>Label</CoreMultiSelectPrim.Label> <CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.Value /> </CoreMultiSelectPrim.Trigger> <CoreMultiSelectPrim.HelperText status="error">에러 메시지가 표시됩니다</CoreMultiSelectPrim.HelperText> <CoreMultiSelectPrim.Portal> <CoreMultiSelectPrim.Content height={200}> <CoreMultiSelectPrim.Item value="option1"> {(sel) => <CoreCheckbox checked={sel} label="Option 1" onChange={() => {}} />} </CoreMultiSelectPrim.Item> <CoreMultiSelectPrim.Item value="option2"> {(sel) => <CoreCheckbox checked={sel} label="Option 2" onChange={() => {}} />} </CoreMultiSelectPrim.Item> </CoreMultiSelectPrim.Content> </CoreMultiSelectPrim.Portal> </CoreMultiSelectPrim.Root> ); }
Props
CoreMultiSelectPrim.Root
Root에 설정한 status / size / width / disabled / readonly / required가 모든 하위 서브 컴포넌트에 자동 전달됩니다.
Prop
Type
CoreMultiSelectPrim.Label
Prop
Type
CoreMultiSelectPrim.Trigger
선택된 값 목록을 보여주는 <button> 요소입니다.
Prop
Type
CoreMultiSelectPrim.Value
Trigger 내부에서 선택된 값 목록을 표시합니다.
Prop
Type
CoreMultiSelectPrim.HelperText
Prop
Type
CoreMultiSelectPrim.Portal
Select.SelectPortalProps를 그대로 수용합니다.
CoreMultiSelectPrim.Content
Prop
Type
CoreMultiSelectPrim.Item
Prop
Type
CoreMultiSelectPrim.Group
Select.SelectGroupProps를 수용합니다.
CoreMultiSelectPrim.GroupLabel
Select.SelectLabelProps를 수용합니다.
CoreMultiSelectPrim.Separator
Select.SelectSeparatorProps를 수용합니다.
CoreTooltipProps
CoreTooltip 컴포넌트의 props를 참조하세요.스타일
SelectPrim과 동일한 디자인 토큰을 공유합니다. CoreSelectPrim 스타일을 참조하세요.
Value 추가 스타일
| valueWrap | flex-wrap | overflow |
|---|---|---|
false | nowrap | hidden |
true | wrap | 없음 |
마이그레이션 가이드
신규 Select 컴포넌트의 multiple 모드로 전환합니다.
| CoreMultiSelectPrim | Select (신규) |
|---|---|
CoreMultiSelectPrim.Root | Select.Root multiple |
CoreMultiSelectPrim.Trigger + Value | Select.Trigger + Select.Value |
CoreMultiSelectPrim.Portal + Content | Select.Popup |
CoreMultiSelectPrim.Item (함수형 children) | Select.Item |
onValueChange: (value: string) => void | onValueChange: (values: string[]) => void |