Select
사용자가 미리 정의된 옵션 목록 중 하나 혹은 하나 이상의 항목을 선택할 수 있는 입력 요소입니다.
Select는 여러 옵션 중 하나의 값을 선택할 수 있습니다.
import { Select, Option, OptionGroup } from '@montage-ui/core';
const Demo = () => {
return (
<Select width="25ch" placeholder="선택해주세요.">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</Select>
)
}
export default Demo;아래와 같은 구조로 조합하여 사용합니다.
SelectMultiple 을 사용하여 여러 옵션 중 하나 이상의 값을 선택할 수 있습니다.
import { SelectMultiple, Option, OptionGroup } from '@montage-ui/core';
const Demo = () => {
return (
<SelectMultiple width="25ch" placeholder="선택해주세요.">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</SelectMultiple>
)
}
export default Demo;render 옵션을 사용하여 텍스트 대신 SelectRenderChip 으로 렌더링 하거나 커스텀 텍스트를 작성할 수 있습니다.
onClick이 들어가는 경우 e.stopPropagation() 을 통해 메뉴가 열리고 닫히는 동작을 막을 수 있습니다.
import { SelectRenderChip, SelectMultiple, Option, OptionGroup } from '@montage-ui/core';
import { useState, useRef } from 'react';
const Demo = () => {
const [value, setValue] = useState(['값 1 0', '값 2 0', '값 0 2']);
const ref = useRef(null);
return (
<SelectMultiple
ref={ref}
value={value}
onChange={setValue}
width="30ch"
placeholder="선택해주세요."
render={() => (
value.map((v, i) => (
<SelectRenderChip
key={v}
onClick={(e) => {
e.stopPropagation();
setValue(value.filter(data => data !== v))
ref.current?.focus();
}}
status={i === 1 ? 'negative' : 'normal'}
disabled={i === 0}
>
{v}
</SelectRenderChip>
))
)}
>
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</SelectMultiple>
)
}
export default Demo;overflow prop 으로 선택된 값이 필드 너비를 넘어갈 때의 동작을 지정합니다.
false(default): 필드를 한 줄로 유지합니다. 텍스트는 말줄임, Chip은 가로 스크롤로 나머지 값을 탐색합니다.true: 값이 모두 보이도록 줄바꿈되며 필드의 높이가 늘어납니다.
Select 는 항상 하나의 값만 가지므로 overflow 를 제공하지 않습니다.
import { FlexBox, SelectMultiple, Option, OptionGroup } from '@montage-ui/core';
const OPTIONS = ['프론트엔드 개발', '백엔드 개발', '데이터 엔지니어링', '프로덕트 디자인', '서비스 기획'];
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<SelectMultiple defaultValue={OPTIONS} width="25ch" placeholder="Overflow false">
<OptionGroup title="그룹 1">
{OPTIONS.map((option) => (
<Option variant="checkbox" key={option} value={option}>{option}</Option>
))}
</OptionGroup>
</SelectMultiple>
<SelectMultiple overflow defaultValue={OPTIONS} width="25ch" placeholder="Overflow true">
<OptionGroup title="그룹 1">
{OPTIONS.map((option) => (
<Option variant="checkbox" key={option} value={option}>{option}</Option>
))}
</OptionGroup>
</SelectMultiple>
</FlexBox>
)
}
export default Demo;import { SelectRenderChip, FlexBox, SelectMultiple, Option, OptionGroup } from '@montage-ui/core';
import { useState, useRef } from 'react';
const OPTIONS = ['프론트엔드 개발', '백엔드 개발', '데이터 엔지니어링', '프로덕트 디자인', '서비스 기획'];
const Demo = () => {
const [scrollValue, setScrollValue] = useState(OPTIONS);
const [wrapValue, setWrapValue] = useState(OPTIONS);
const scrollRef = useRef(null);
const wrapRef = useRef(null);
const renderChips = (value, setValue, ref) => () => (
value.map((v) => (
<SelectRenderChip
key={v}
onClick={(e) => {
e.stopPropagation();
setValue(value.filter((data) => data !== v));
ref.current.focus();
}}
>
{v}
</SelectRenderChip>
))
);
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<SelectMultiple
width="25ch"
placeholder="Overflow false"
value={scrollValue}
onChange={setScrollValue}
ref={scrollRef}
render={renderChips(scrollValue, setScrollValue, scrollRef)}
>
<OptionGroup title="그룹 1">
{OPTIONS.map((option) => (
<Option variant="checkbox" key={option} value={option}>{option}</Option>
))}
</OptionGroup>
</SelectMultiple>
<SelectMultiple
overflow
width="25ch"
placeholder="Overflow true"
value={wrapValue}
onChange={setWrapValue}
ref={wrapRef}
render={renderChips(wrapValue, setWrapValue, wrapRef)}
>
<OptionGroup title="그룹 1">
{OPTIONS.map((option) => (
<Option variant="checkbox" key={option} value={option}>{option}</Option>
))}
</OptionGroup>
</SelectMultiple>
</FlexBox>
)
}
export default Demo;allSelectedLabel prop을 사용하여 모든 옵션이 선택되었을 때 표시할 label을 커스텀할 수 있습니다.
import { SelectMultiple, Option, OptionGroup } from '@montage-ui/core';
const Demo = () => {
return (
<SelectMultiple defaultValue={['값 0 0', '값 0 1', '값 0 2']} width="25ch" placeholder="선택해주세요." allSelectedLabel="전체">
{new Array(1).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</SelectMultiple>
)
}
export default Demo;Option 컴포넌트에 variant prop을 주어 다양한 형태의 옵션을 렌더링 할 수 있습니다.
- normal (default)
- radio (single only)
- checkbox (multiple only)
import { SelectMultiple, Select, Option, OptionGroup, FlexBox } from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<Select width="25ch" placeholder="Normal">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option variant="normal" key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</Select>
<Select width="25ch" placeholder="Radio">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option variant="radio" key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</Select>
<SelectMultiple width="25ch" placeholder="Checkbox">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option variant="checkbox" key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</SelectMultiple>
</FlexBox>
)
}
export default Demo;validation 을 통해 여러 상태를 표현할 수 있습니다.
- default
- negative (
status="negative") - disabled
import { Select, Option, OptionGroup, FlexBox } from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<Select width="25ch" placeholder="선택해주세요.">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</Select>
<Select status="negative" width="25ch" placeholder="선택해주세요.">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</Select>
<Select disabled width="25ch" placeholder="선택해주세요.">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</Select>
<Select disabled width="25ch" placeholder="선택해주세요." value="값 0 0">
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
</Select>
</FlexBox>
)
}
export default Demo;2가지 사이즈를 제공합니다.
- large (default)
- medium
import { FlexBox, FormControl, FormControlField, FormControlLabel, FormControlMessage, Select, Option, OptionGroup } from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<FormControl size="large">
<FormControlLabel required>Large</FormControlLabel>
<FormControlField>
<Select size="large" width="25ch" placeholder="Large">
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
</FormControlField>
<FormControlMessage>Helper Message</FormControlMessage>
</FormControl>
<FormControl size="medium">
<FormControlLabel required>Medium</FormControlLabel>
<FormControlField>
<Select size="medium" width="25ch" placeholder="Medium">
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
</FormControlField>
<FormControlMessage>Helper Message</FormControlMessage>
</FormControl>
</FlexBox>
)
}
export default Demo;SelectMultiple 도 동일한 사이즈 체계를 사용합니다.
import { FlexBox, SelectRenderChip, SelectMultiple, Option, OptionGroup, FormControl, FormControlField, FormControlLabel, FormControlMessage } from '@montage-ui/core';
import { useState, useRef } from 'react';
const OPTIONS = ['프론트엔드 개발', '백엔드 개발', '데이터 엔지니어링', '프로덕트 디자인', '서비스 기획'];
const Demo = () => {
const [mediumValue, setMediumValue] = useState(OPTIONS);
const [largeValue, setLargeValue] = useState(OPTIONS);
const mediumRef = useRef(null);
const largeRef = useRef(null);
const renderChips = (value, setValue, ref) => () => (
value.map((v) => (
<SelectRenderChip
key={v}
onClick={(e) => {
e.stopPropagation();
setValue(value.filter((data) => data !== v));
ref.current.focus();
}}
>
{v}
</SelectRenderChip>
))
);
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<FormControl size="large">
<FormControlLabel required>Large</FormControlLabel>
<FormControlField>
<SelectMultiple size="large" width="25ch" placeholder="Large">
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
</FormControlField>
<FormControlMessage>Helper Message</FormControlMessage>
</FormControl>
<FormControl size="medium">
<FormControlLabel required>Medium</FormControlLabel>
<FormControlField>
<SelectMultiple size="medium" width="25ch" placeholder="Medium">
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
</FormControlField>
<FormControlMessage>Helper Message</FormControlMessage>
</FormControl>
<FormControl size="large">
<FormControlLabel required>Large</FormControlLabel>
<FormControlField>
<SelectMultiple
size="large"
width="25ch"
placeholder="Large with chip"
value={largeValue}
onChange={setLargeValue}
ref={largeRef}
render={renderChips(largeValue, setLargeValue, largeRef)}
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
</FormControlField>
<FormControlMessage>Helper Message</FormControlMessage>
</FormControl>
<FormControl size="medium">
<FormControlLabel required>Medium</FormControlLabel>
<FormControlField>
<SelectMultiple
size="medium"
width="25ch"
placeholder="Medium with chip"
value={mediumValue}
onChange={setMediumValue}
ref={mediumRef}
render={renderChips(mediumValue, setMediumValue, mediumRef)}
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
</FormControlField>
<FormControlMessage>Helper Message</FormControlMessage>
</FormControl>
</FlexBox>
)
}
export default Demo;Select, SelectMultiple 컴포넌트에 leadingContent prop 을 사용하여 요소의 앞쪽에 콘텐츠를 추가할 수 있습니다.
해당 옵션을 사용할 때에는 SelectContent 로 감싸서 사용합니다.
icon-button 의 IconButton 은 size 를 지정하지 않으면 Select size(반응형 포함)에 맞는 size 와 interactionOverflow 가 자동으로 적용됩니다. IconButton 에 직접 지정하면 지정한 값이 우선합니다.
또한 IconButton 클릭 시 메뉴가 열리지 않도록 e.stopPropagation() 을 함께 사용합니다.
import { SelectRenderChip, Select, SelectMultiple, Option, OptionGroup, SelectContent, FlexBox, IconButton } from '@montage-ui/core';
import { IconBlank } from '@montage-ui/icon';
import { useState, useRef } from 'react';
const OPTIONS = ['프론트엔드 개발', '백엔드 개발', '데이터 엔지니어링', '프로덕트 디자인', '서비스 기획'];
const Demo = () => {
const [iconValue, setIconValue] = useState([]);
const [iconButtonValue, setIconButtonValue] = useState([]);
const iconRef = useRef(null);
const iconButtonRef = useRef(null);
const renderChips = (value, setValue, ref) => () => (
value.map((v) => (
<SelectRenderChip
key={v}
onClick={(e) => {
e.stopPropagation();
setValue(value.filter((data) => data !== v));
ref.current.focus();
}}
>
{v}
</SelectRenderChip>
))
);
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<Select
size="large"
width="25ch"
placeholder="Icon"
leadingContent={(
<SelectContent variant="icon">
<IconBlank />
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
<Select
size="large"
width="25ch"
placeholder="Icon button"
leadingContent={(
<SelectContent variant="icon-button">
<IconButton onClick={(e) => e.stopPropagation()}>
<IconBlank />
</IconButton>
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
<SelectMultiple
size="large"
width="25ch"
placeholder="Multiple, Icon"
leadingContent={(
<SelectContent variant="icon">
<IconBlank />
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
<SelectMultiple
size="large"
width="25ch"
placeholder="Multiple, Icon button"
leadingContent={(
<SelectContent variant="icon-button">
<IconButton onClick={(e) => e.stopPropagation()}>
<IconBlank />
</IconButton>
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
<SelectMultiple
size="large"
width="25ch"
placeholder="Multiple, Icon, chip"
ref={iconRef}
value={iconValue}
onChange={setIconValue}
render={renderChips(iconValue, setIconValue, iconRef)}
leadingContent={(
<SelectContent variant="icon">
<IconBlank />
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
<SelectMultiple
size="large"
width="25ch"
placeholder="Multiple, Icon button, chip"
ref={iconButtonRef}
value={iconButtonValue}
onChange={setIconButtonValue}
render={renderChips(iconButtonValue, setIconButtonValue, iconButtonRef)}
leadingContent={(
<SelectContent variant="icon-button">
<IconButton onClick={(e) => e.stopPropagation()}>
<IconBlank />
</IconButton>
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
</FlexBox>
)
}
export default Demo;import { SelectRenderChip, Select, SelectMultiple, Option, OptionGroup, SelectContent, FlexBox, IconButton } from '@montage-ui/core';
import { IconBlank } from '@montage-ui/icon';
import { useState, useRef } from 'react';
const OPTIONS = ['프론트엔드 개발', '백엔드 개발', '데이터 엔지니어링', '프로덕트 디자인', '서비스 기획'];
const Demo = () => {
const [iconValue, setIconValue] = useState([]);
const [iconButtonValue, setIconButtonValue] = useState([]);
const iconRef = useRef(null);
const iconButtonRef = useRef(null);
const renderChips = (value, setValue, ref) => () => (
value.map((v) => (
<SelectRenderChip
key={v}
onClick={(e) => {
e.stopPropagation();
setValue(value.filter((data) => data !== v));
ref.current.focus();
}}
>
{v}
</SelectRenderChip>
))
);
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<Select
size="medium"
width="25ch"
placeholder="Icon"
leadingContent={(
<SelectContent variant="icon">
<IconBlank />
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
<Select
size="medium"
width="25ch"
placeholder="Icon button"
leadingContent={(
<SelectContent variant="icon-button">
<IconButton onClick={(e) => e.stopPropagation()}>
<IconBlank />
</IconButton>
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
<SelectMultiple
size="medium"
width="25ch"
placeholder="Multiple, Icon"
leadingContent={(
<SelectContent variant="icon">
<IconBlank />
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
<SelectMultiple
size="medium"
width="25ch"
placeholder="Multiple, Icon button"
leadingContent={(
<SelectContent variant="icon-button">
<IconButton onClick={(e) => e.stopPropagation()}>
<IconBlank />
</IconButton>
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
<SelectMultiple
size="medium"
width="25ch"
placeholder="Multiple, Icon, chip"
ref={iconRef}
value={iconValue}
onChange={setIconValue}
render={renderChips(iconValue, setIconValue, iconRef)}
leadingContent={(
<SelectContent variant="icon">
<IconBlank />
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
<SelectMultiple
size="medium"
width="25ch"
placeholder="Multiple, Icon button, chip"
ref={iconButtonRef}
value={iconButtonValue}
onChange={setIconButtonValue}
render={renderChips(iconButtonValue, setIconButtonValue, iconButtonRef)}
leadingContent={(
<SelectContent variant="icon-button">
<IconButton onClick={(e) => e.stopPropagation()}>
<IconBlank />
</IconButton>
</SelectContent>
)}
>
<OptionGroup title="그룹 1">
<Option variant="checkbox" value="옵션1">옵션1</Option>
<Option variant="checkbox" value="옵션2">옵션2</Option>
</OptionGroup>
</SelectMultiple>
</FlexBox>
)
}
export default Demo;Option 컴포넌트에 leadingContent, trailingContent prop 을 사용하여 옵션의 앞/뒤에 콘텐츠를 추가할 수 있습니다.
OptionContent 로 감싸서 사용합니다.
import { Select, Option, OptionContent, FlexBox, IconButton, Avatar, ContentBadge } from '@montage-ui/core';
import { IconBlank } from '@montage-ui/icon';
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<Select width="25ch" placeholder="Option content">
<Option
value="1"
trailingContent={(
<OptionContent variant="value" chevron>
값
</OptionContent>
)}
>
Chevron
</Option>
<Option
value="2"
alignItems="center"
leadingContent={(
<OptionContent variant="avatar">
<Avatar />
</OptionContent>
)}
>
Avatar
</Option>
<Option
value="3"
alignItems="center"
trailingContent={(
<OptionContent variant="content-badge">
<ContentBadge>
Badge
</ContentBadge>
</OptionContent>
)}
>
Badge
</Option>
</Select>
</FlexBox>
)
}
export default Demo;Option 컴포넌트에 labelTrailing prop 을 사용하여 레이블 우측에 콘텐츠를 추가할 수 있습니다.
OptionLabelTrailing 으로 감싸서 사용합니다.
import { Select, Option, OptionLabelTrailing, FlexBox, ContentBadge } from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<Select width="25ch" placeholder="Option label trailing">
<Option
value="1"
labelTrailing={(
<OptionLabelTrailing variant="verified-check" />
)}
>
Verified check
</Option>
<Option
value="2"
labelTrailing={(
<OptionLabelTrailing variant="content-badge">
<ContentBadge color="neutral">Badge</ContentBadge>
</OptionLabelTrailing>
)}
>
Content badge
</Option>
</Select>
</FlexBox>
)
}
export default Demo;Option 컴포넌트에 extraContent prop 을 사용하여 텍스트 영역 하단에 추가 콘텐츠를 추가할 수 있습니다.
OptionExtraContent 로 감싸서 사용합니다.
import { Select, Option, OptionExtraContent, FlexBox, ContentBadge } from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<Select width="25ch" placeholder="Option extra content">
<Option
value="1"
extraContent={(
<OptionExtraContent variant="text">
Extra text
</OptionExtraContent>
)}
>
Text
</Option>
<Option
value="2"
extraContent={(
<OptionExtraContent variant="content-badge">
<ContentBadge color="neutral">Badge</ContentBadge>
</OptionExtraContent>
)}
>
Content badge
</Option>
</Select>
</FlexBox>
)
}
export default Demo;Action Area 영역을 추가할 수 있습니다.
Action Area 영역을 사용한다면 enableMenuActionArea prop 을 주어 value 와 menuValue 두 가지 상태로 관리할 수 있습니다.
- value: 실제 값
- menuValue: 메뉴에서 선택된 값
import { Select, Option, OptionGroup, MenuActionArea, MenuActionAreaContent, Button } from '@montage-ui/core';
import { IconRefresh } from '@montage-ui/icon';
import { useState } from 'react';
const Demo = () => {
const [value, setValue] = useState('');
const [menuValue, setMenuValue] = useState('');
const [open, setOpen] = useState(false);
return (
<Select
enableMenuActionArea
open={open}
onOpenChange={setOpen}
value={value}
onChange={setValue}
menuValue={menuValue}
onMenuValueChange={setMenuValue}
width="25ch"
placeholder="선택해주세요."
>
{new Array(3).fill(0).map((_, i) => (
<OptionGroup key={i} title={`그룹 ${i + 1}`}>
{new Array(3).fill(0)
.map((__, j) => (
<Option key={j} value={`값 ${i} ${j}`}>
{`값 ${i} ${j}`}
</Option>
))
}
</OptionGroup>
))}
<MenuActionArea
leadingContent={
<MenuActionAreaContent variant="button">
<Button
variant="outlined"
color="assistive"
iconOnly
onClick={() => setMenuValue('')}
>
<IconRefresh />
</Button>
</MenuActionAreaContent>
}
trailingContent={
<MenuActionAreaContent variant="button">
<Button onClick={() => {
setValue(menuValue);
setOpen(false);
}}>
적용
</Button>
</MenuActionAreaContent>
}
/>
</Select>
)
}
export default Demo;Form과 관련된 컴포넌트와 함께 사용할 수 있습니다.
FormControlGroupFormControlFormControlFieldFormControlLabelFormControlMessageFormControlNegativeMessageFormControlPositiveMessageFormControlMessageAccessory
import { FlexBox, FormControl, FormControlField, FormControlLabel, FormControlMessage, FormControlNegativeMessage, Select, Option, OptionGroup } from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexDirection="column" alignItems="center">
<FormControl>
<FormControlLabel required>Label</FormControlLabel>
<FormControlField>
<Select width="25ch" placeholder="Form control">
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
</FormControlField>
<FormControlMessage>Helper Message</FormControlMessage>
</FormControl>
<FormControl>
<FormControlLabel required>Label</FormControlLabel>
<FormControlField>
<Select width="25ch" placeholder="Invalid form control" status="negative">
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
</FormControlField>
<FormControlNegativeMessage>Error Message</FormControlNegativeMessage>
</FormControl>
</FlexBox>
)
}
export default Demo;기본적으로 비제어 컴포넌트로 동작합니다.
value, onChange prop을 사용하면 제어 컴포넌트로 동작합니다.
제어 컴포넌트와 비제어 컴포넌트는 React 공식 문서를 참조해주세요.
import { FlexBox, Select, Option, OptionGroup } from '@montage-ui/core';
import { useState } from 'react';
const Demo = () => {
const [value, setValue] = useState('');
return (
<FlexBox alignItems="center" flexDirection="column" gap="12px">
<Select
defaultValue="옵션1"
width="25ch"
placeholder="Uncontrolled"
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
<Select
value={value}
onChange={setValue}
width="25ch"
placeholder="Controlled"
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
</FlexBox>
)
}
export default Demo;react-hook-form과 유연하게 조합해서 사용할 수 있습니다.
import { Button, FlexBox, Select, Option, OptionGroup, FormControl, FormControlField, FormControlLabel, FormControlNegativeMessage, FormControlMessage } from '@montage-ui/core';
import { useForm, Controller } from 'react-hook-form';
const Demo = () => {
const form = useForm();
return (
<FlexBox
as="form"
flexDirection="column"
alignItems="center"
justifyContent="center"
gap="20px"
onSubmit={form.handleSubmit((v) => alert(JSON.stringify(v)))}
>
<Controller
control={form.control}
name="selection"
rules={{
required: {
value: true,
message: "필수 값입니다.",
},
}}
render={({ field, formState }) => (
<FormControl>
<FormControlLabel required>선택</FormControlLabel>
<FormControlField>
<Select
{...field}
placeholder="선택하세요."
width="300px"
status={Boolean(formState.errors.selection) ? 'negative' : 'normal'}
>
<OptionGroup title="그룹 1">
<Option value="옵션1">옵션1</Option>
<Option value="옵션2">옵션2</Option>
</OptionGroup>
</Select>
</FormControlField>
{!!formState.errors.selection ? (
<FormControlNegativeMessage>{formState.errors.selection?.message?.toString()}</FormControlNegativeMessage>
) : (
<FormControlMessage>옵션을 선택하세요.</FormControlMessage>
)}
</FormControl>
)}
/>
<Button type="submit" fullWidth>제출</Button>
</FlexBox>
)
}
export default Demo;WAI-ARIA Combobox Pattern 대부분을 준수합니다.
- Form Control 와 함께 사용할 때 모든 접근성 속성을 주입할 수 있습니다.
- 그렇지 않은 경우에는 직접
aria-label등을 사용해서 접근성을 충족시켜야 합니다.
ListCellLabelTrailing과 동일한 props를 사용합니다.
ListCellExtraContent와 동일한 props를 사용합니다.
