셀렉트
셀렉트 (Select)
드롭다운 메뉴로 여러 선택지를 보여주고, 사용자가 하나 또는 여러 개를 고를 수 있게 해주는 컴포넌트입니다. 검색, 태그 입력, 그룹 등 다양한 시나리오에서 폭넓게 쓰여요.
출처: 문서
본문
언제 사용하나요 (When To Use)
- 선택지를 보여주는 드롭다운 메뉴 - 기본
<select>요소의 우아한 대안입니다. - 전체 옵션이 적다면(5개 미만) Radio 사용을 권장합니다.
- 입력과 선택이 모두 가능한 입력창을 찾고 있다면 AutoComplete이 필요할 것입니다.
예제 (Examples)
기본 사용법 (Basic Usage)
기본 사용법입니다.
import React from 'react';
import { Select, Space } from 'antd';
const handleChange = (value: string) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<Space wrap>
<Select
defaultValue="lucy"
style={{ width: 120 }}
onChange={handleChange}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
<Select
defaultValue="lucy"
style={{ width: 120 }}
disabled
options={[{ value: 'lucy', label: 'Lucy' }]}
/>
<Select
defaultValue="lucy"
style={{ width: 120 }}
loading
options={[{ value: 'lucy', label: 'Lucy' }]}
/>
<Select
defaultValue="lucy"
style={{ width: 120 }}
allowClear
options={[{ value: 'lucy', label: 'Lucy' }]}
placeholder="select it"
/>
</Space>
);
export default App;
검색 기능이 있는 Select (Select with search field)
펼쳐진 상태에서 옵션을 검색합니다.
import React from 'react';
import { Select } from 'antd';
const onChange = (value: string) => {
console.log(`selected ${value}`);
};
const onSearch = (value: string) => {
console.log('search:', value);
};
const App: React.FC = () => (
<Select
showSearch={{ optionFilterProp: 'label', onSearch }}
placeholder="Select a person"
onChange={onChange}
options={[
{
value: 'jack',
label: 'Jack',
},
{
value: 'lucy',
label: 'Lucy',
},
{
value: 'tom',
label: 'Tom',
},
]}
/>
);
export default App;
커스텀 검색 (Custom Search)
filterOption을 사용해 검색을 커스터마이즈합니다.
import React from 'react';
import { Select } from 'antd';
const App: React.FC = () => (
<Select
showSearch={{
filterOption: (input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase()),
}}
placeholder="Select a person"
options={[
{ value: '1', label: 'Jack' },
{ value: '2', label: 'Lucy' },
{ value: '3', label: 'Tom' },
]}
/>
);
export default App;
다중 필드 검색 (Multi field search)
optionFilterProp을 사용해 다중 필드 검색을 수행합니다.
import React from 'react';
import { Select } from 'antd';
const App: React.FC = () => (
<Select
placeholder="Select an option"
showSearch={{
optionFilterProp: ['label', 'otherField'],
}}
options={[
{ value: 'a11', label: 'a11', otherField: 'c11' },
{ value: 'b22', label: 'b22', otherField: 'b11' },
{ value: 'c33', label: 'c33', otherField: 'b33' },
{ value: 'd44', label: 'd44', otherField: 'd44' },
]}
/>
);
export default App;
다중 선택 (multiple selection)
기존 항목에서 선택하는 다중 선택입니다.
import React from 'react';
import { Select, Space } from 'antd';
import type { SelectProps } from 'antd';
const options: SelectProps['options'] = [];
for (let i = 10; i < 36; i++) {
options.push({
label: i.toString(36) + i,
value: i.toString(36) + i,
});
}
const handleChange = (value: string[]) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<Space style={{ width: '100%' }} vertical>
<Select
mode="multiple"
allowClear
style={{ width: '100%' }}
placeholder="Please select"
defaultValue={['a10', 'c12']}
onChange={handleChange}
options={options}
/>
<Select
mode="multiple"
disabled
style={{ width: '100%' }}
placeholder="Please select"
defaultValue={['a10', 'c12']}
onChange={handleChange}
options={options}
/>
</Space>
);
export default App;
크기 (Sizes)
Select의 입력 필드 높이는 기본적으로 32px입니다. size를 large로 설정하면 40px, small로 설정하면 24px가 됩니다.
import React, { useState } from 'react';
import { Radio, Select, Space } from 'antd';
import type { ConfigProviderProps, RadioChangeEvent, SelectProps } from 'antd';
type SizeType = ConfigProviderProps['componentSize'];
const options: SelectProps['options'] = [];
for (let i = 10; i < 36; i++) {
options.push({
value: i.toString(36) + i,
label: i.toString(36) + i,
});
}
const handleChange = (value: string | string[]) => {
console.log(`Selected: ${value}`);
};
const App: React.FC = () => {
const [size, setSize] = useState<SizeType>('medium');
const handleSizeChange = (e: RadioChangeEvent) => {
setSize(e.target.value);
};
return (
<>
<Radio.Group value={size} onChange={handleSizeChange}>
<Radio.Button value="large">Large</Radio.Button>
<Radio.Button value="medium">Medium</Radio.Button>
<Radio.Button value="small">Small</Radio.Button>
</Radio.Group>
<br />
<br />
<Space vertical style={{ width: '100%' }}>
<Select
size={size}
defaultValue="a1"
onChange={handleChange}
style={{ width: 200 }}
options={options}
/>
<Select
mode="multiple"
size={size}
placeholder="Please select"
defaultValue={['a10', 'c12']}
onChange={handleChange}
style={{ width: '100%' }}
options={options}
/>
<Select
mode="tags"
size={size}
placeholder="Please select"
defaultValue={['a10', 'c12']}
onChange={handleChange}
style={{ width: '100%' }}
options={options}
/>
</Space>
</>
);
};
export default App;
커스텀 드롭다운 옵션 (Custom dropdown options)
optionRender를 사용해 드롭다운 옵션 렌더링을 커스터마이즈합니다.
import React from 'react';
import { Select, Space } from 'antd';
const options = [
{
label: 'Happy',
value: 'happy',
emoji: '😄',
desc: 'Feeling Good',
},
{
label: 'Sad',
value: 'sad',
emoji: '😢',
desc: 'Feeling Blue',
},
{
label: 'Angry',
value: 'angry',
emoji: '😡',
desc: 'Furious',
},
{
label: 'Cool',
value: 'cool',
emoji: '😎',
desc: 'Chilling',
},
{
label: 'Sleepy',
value: 'sleepy',
emoji: '😴',
desc: 'Need Sleep',
},
];
const App: React.FC = () => (
<Select
mode="multiple"
style={{ width: '100%' }}
placeholder="Please select your current mood."
defaultValue={['happy']}
onChange={(value) => {
console.log(`selected ${value}`);
}}
options={options}
optionRender={(option) => (
<Space>
<span role="img" aria-label={option.data.label}>
{option.data.emoji}
</span>
{`${option.data.label} (${option.data.desc})`}
</Space>
)}
/>
);
export default App;
정렬과 함께 검색 (Search with sort)
정렬과 함께 옵션을 검색합니다.
import React from 'react';
import { Select } from 'antd';
const App: React.FC = () => (
<Select
showSearch={{
optionFilterProp: 'label',
filterSort: (optionA, optionB) =>
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()),
}}
style={{ width: 200 }}
placeholder="Search to Select"
options={[
{
value: '1',
label: 'Not Identified',
},
{
value: '2',
label: 'Closed',
},
{
value: '3',
label: 'Communicated',
},
{
value: '4',
label: 'Identified',
},
{
value: '5',
label: 'Resolved',
},
{
value: '6',
label: 'Cancelled',
},
]}
/>
);
export default App;
태그 (Tags)
리스트에서 태그를 선택하거나 커스텀 태그를 직접 입력할 수 있습니다.
import React from 'react';
import { Select } from 'antd';
import type { SelectProps } from 'antd';
const options: SelectProps['options'] = [];
for (let i = 10; i < 36; i++) {
options.push({
value: i.toString(36) + i,
label: i.toString(36) + i,
});
}
const handleChange = (value: string[]) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<Select
mode="tags"
style={{ width: '100%' }}
placeholder="Tags Mode"
onChange={handleChange}
options={options}
/>
);
export default App;
옵션 그룹 (Option Group)
OptGroup을 사용해 옵션을 그룹화합니다.
import React from 'react';
import { Select } from 'antd';
const handleChange = (value: string) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<Select
defaultValue="lucy"
style={{ width: 200 }}
onChange={handleChange}
options={[
{
label: <span>manager</span>,
title: 'manager',
options: [
{ label: <span>Jack</span>, value: 'Jack' },
{ label: <span>Lucy</span>, value: 'Lucy' },
],
},
{
label: <span>engineer</span>,
title: 'engineer',
options: [
{ label: <span>Chloe</span>, value: 'Chloe' },
{ label: <span>Lucas</span>, value: 'Lucas' },
],
},
]}
/>
);
export default App;
연동 (coordinate)
시·도를 연동해서 선택하는 것은 흔한 사용 사례로, 선택 연동을 보여줍니다. 이 경우 Cascader 컴포넌트를 적극 권장합니다.
import React, { useState } from 'react';
import { Select, Space } from 'antd';
const cityData = {
Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],
Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang'],
};
type CityName = keyof typeof cityData;
const provinceData: CityName[] = ['Zhejiang', 'Jiangsu'];
const App: React.FC = () => {
const [cities, setCities] = useState(cityData[provinceData[0] as CityName]);
const [secondCity, setSecondCity] = useState(cityData[provinceData[0]][0] as CityName);
const handleProvinceChange = (value: CityName) => {
setCities(cityData[value]);
setSecondCity(cityData[value][0] as CityName);
};
const onSecondCityChange = (value: CityName) => {
setSecondCity(value);
};
return (
<Space wrap>
<Select
defaultValue={provinceData[0]}
style={{ width: 120 }}
onChange={handleProvinceChange}
options={provinceData.map((province) => ({ label: province, value: province }))}
/>
<Select
style={{ width: 120 }}
value={secondCity}
onChange={onSecondCityChange}
options={cities.map((city) => ({ label: city, value: city }))}
/>
</Space>
);
};
export default App;
선택 항목의 값 가져오기 (Get value of selected item)
기본 동작으로 onChange 콜백은 선택 항목의 value만 가져올 수 있습니다. labelInValue prop을 사용하면 선택 항목의 label 속성도 가져올 수 있습니다.
선택 항목의 label은 onChange 콜백에 전달하기 위해 객체로 묶여 제공됩니다.
import React from 'react';
import { Select } from 'antd';
const handleChange = (value: { value: string; label: React.ReactNode }) => {
console.log(value); // { value: "lucy", key: "lucy", label: "Lucy (101)" }
};
const App: React.FC = () => (
<Select
labelInValue
defaultValue={{ value: 'lucy', label: 'Lucy (101)' }}
style={{ width: 120 }}
onChange={handleChange}
options={[
{
value: 'jack',
label: 'Jack (100)',
},
{
value: 'lucy',
label: 'Lucy (101)',
},
]}
/>
);
export default App;
자동 토큰화 (Automatic tokenization)
Lucy,Jack을 복사해 입력창에 붙여넣어 보세요. tags와 multiple 모드에서만 사용할 수 있습니다.
import React from 'react';
import { Select } from 'antd';
import type { SelectProps } from 'antd';
const options: SelectProps['options'] = [];
for (let i = 10; i < 36; i++) {
options.push({
value: i.toString(36) + i,
label: i.toString(36) + i,
});
}
const handleChange = (value: string[]) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<Select
mode="tags"
style={{ width: '100%' }}
onChange={handleChange}
tokenSeparators={[',']}
options={options}
/>
);
export default App;
커스텀 토큰화 (Custom tokenization)
자신의 규칙으로 입력을 분리하도록 토큰화 로직을 커스터마이즈합니다.
import React from 'react';
import { Select } from 'antd';
const tokenize = (input: string): string[] => {
const tokens: string[] = [];
const regex = /"([^"]*)"|([^,\n]+)/g;
let match: RegExpExecArray | null = regex.exec(input);
while (match) {
tokens.push((match[1] ?? match[2]).trim());
match = regex.exec(input);
}
return tokens.filter(Boolean);
};
const App: React.FC = () => (
<Select
mode="tags"
style={{ width: '100%' }}
tokenSeparators={tokenize}
placeholder='Try paste: "San Francisco, CA", New York'
/>
);
export default App;
사용자 검색 및 선택 (Search and Select Users)
원격 검색, 디바운스 fetch, ajax 콜백 순서 흐름, 로딩 상태가 포함된 완전한 다중 선택 예제입니다.
import React, { useMemo, useRef, useState } from 'react';
import { Avatar, Select, Spin } from 'antd';
import type { SelectProps } from 'antd';
import debounce from 'lodash/debounce';
export interface DebounceSelectProps<ValueType = any>
extends Omit<SelectProps<ValueType | ValueType[]>, 'options' | 'children'> {
fetchOptions: (search: string) => Promise<ValueType[]>;
debounceTimeout?: number;
}
function DebounceSelect<
ValueType extends {
key?: string;
label: React.ReactNode;
value: string | number;
avatar?: string;
} = any,
>({ fetchOptions, debounceTimeout = 300, ...props }: DebounceSelectProps<ValueType>) {
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState<ValueType[]>([]);
const fetchRef = useRef(0);
const debounceFetcher = useMemo(() => {
const loadOptions = (value: string) => {
fetchRef.current += 1;
const fetchId = fetchRef.current;
setOptions([]);
setFetching(true);
fetchOptions(value).then((newOptions) => {
if (fetchId !== fetchRef.current) {
// for fetch callback order
return;
}
setOptions(newOptions);
setFetching(false);
});
};
return debounce(loadOptions, debounceTimeout);
}, [fetchOptions, debounceTimeout]);
return (
<Select
labelInValue
showSearch={{
autoClearSearchValue: false,
filterOption: false,
onSearch: debounceFetcher,
}}
notFoundContent={fetching ? <Spin size="small" /> : 'No results found'}
{...props}
options={options}
optionRender={(option) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
{option.data.avatar && <Avatar src={option.data.avatar} style={{ marginInlineEnd: 8 }} />}
{option.label}
</div>
)}
/>
);
}
// Usage of DebounceSelect
interface UserValue {
label: string;
value: string;
avatar?: string;
}
async function fetchUserList(username: string): Promise<UserValue[]> {
console.log('fetching user', username);
return fetch(`https://660d2bd96ddfa2943b33731c.mockapi.io/api/users/?search=${username}`)
.then((res) => res.json())
.then((res) => {
const results = Array.isArray(res) ? res : [];
return results.map<UserValue>((user) => ({
label: user.name,
value: user.id,
avatar: user.avatar,
}));
})
.catch(() => {
console.log('fetch mock data failed');
return [];
});
}
const App: React.FC = () => {
const [value, setValue] = useState<UserValue[]>([]);
return (
<DebounceSelect
mode="multiple"
value={value}
placeholder="Select users"
fetchOptions={fetchUserList}
style={{ width: '100%' }}
onChange={(newValue) => {
if (Array.isArray(newValue)) {
setValue(newValue);
}
}}
/>
);
};
export default App;
접두사와 접미사 (Prefix and Suffix)
커스텀 prefix와 suffixIcon을 설정합니다.
import React from 'react';
import { MehOutlined, SmileOutlined } from '@ant-design/icons';
import { Select, Space } from 'antd';
const smileIcon = <SmileOutlined />;
const mehIcon = <MehOutlined />;
const handleChange = (value: string | string[]) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<Space wrap>
<Select
prefix="User"
defaultValue="lucy"
placeholder="Select User"
style={{ width: 200 }}
onChange={handleChange}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
allowClear
showSearch
/>
<Select
suffixIcon={smileIcon}
defaultValue="lucy"
placeholder="Select"
style={{ width: 120 }}
onChange={handleChange}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
<Select
suffixIcon={mehIcon}
defaultValue="lucy"
placeholder="Select"
style={{ width: 120 }}
disabled
options={[{ value: 'lucy', label: 'Lucy' }]}
/>
<br />
<Select
prefix="User"
defaultValue={['lucy']}
placeholder="Select"
mode="multiple"
style={{ width: 200 }}
onChange={handleChange}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
<Select
suffixIcon={smileIcon}
defaultValue={['lucy']}
placeholder="Select"
mode="multiple"
style={{ width: 120 }}
onChange={handleChange}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
<Select
suffixIcon={mehIcon}
defaultValue={['lucy']}
placeholder="Select"
mode="multiple"
style={{ width: 120 }}
disabled
options={[{ value: 'lucy', label: 'Lucy' }]}
/>
</Space>
);
export default App;
커스텀 드롭다운 (Custom dropdown)
popupRender를 통해 드롭다운 메뉴를 커스터마이즈합니다. 커스텀 콘텐츠를 클릭한 뒤 드롭다운을 닫으려면 open prop을 제어해야 합니다. 여기에 codesandbox 예시가 있습니다.
import React, { useRef, useState } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import { Button, Divider, Input, Select, Space } from 'antd';
import type { InputRef } from 'antd';
let index = 0;
const App: React.FC = () => {
const [items, setItems] = useState(['jack', 'lucy']);
const [name, setName] = useState('');
const inputRef = useRef<InputRef>(null);
const onNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setName(event.target.value);
};
const addItem = (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
e.preventDefault();
setItems([...items, name || `New item ${index++}`]);
setName('');
setTimeout(() => {
inputRef.current?.focus();
}, 0);
};
return (
<Select
style={{ width: 300 }}
placeholder="custom dropdown render"
popupRender={(menu) => (
<>
{menu}
<Divider style={{ margin: '8px 0' }} />
<Space style={{ padding: '0 8px 4px' }}>
<Input
placeholder="Please enter item"
ref={inputRef}
value={name}
onChange={onNameChange}
onKeyDown={(e) => e.stopPropagation()}
/>
<Button type="text" icon={<PlusOutlined />} onClick={addItem}>
Add item
</Button>
</Space>
</>
)}
options={items.map((item) => ({ label: item, value: item }))}
/>
);
};
export default App;
이미 선택된 항목 숨기기 (Hide Already Selected)
드롭다운에서 이미 선택된 옵션을 숨깁니다.
import React, { useState } from 'react';
import { Select } from 'antd';
const OPTIONS = ['Apples', 'Nails', 'Bananas', 'Helicopters'];
const App: React.FC = () => {
const [selectedItems, setSelectedItems] = useState<string[]>([]);
const filteredOptions = OPTIONS.filter((o) => !selectedItems.includes(o));
return (
<Select
mode="multiple"
placeholder="Inserted are removed"
value={selectedItems}
onChange={setSelectedItems}
style={{ width: '100%' }}
options={filteredOptions.map((item) => ({
value: item,
label: item,
}))}
/>
);
};
export default App;
변형 (Variants)
Select의 변형은 outlined, filled, borderless, underlined 네 가지입니다.
import React from 'react';
import { Flex, Select } from 'antd';
const App: React.FC = () => (
<Flex gap={12} vertical>
<Flex gap={8}>
<Select
placeholder="Outlined"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
<Select
mode="multiple"
defaultValue={['lucy']}
placeholder="Outlined"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
</Flex>
<Flex gap={8}>
<Select
placeholder="Filled"
variant="filled"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
<Select
mode="multiple"
defaultValue={['lucy']}
placeholder="Filled"
variant="filled"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
</Flex>
<Flex gap={8}>
<Select
placeholder="Borderless"
variant="borderless"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
<Select
mode="multiple"
defaultValue={['lucy']}
placeholder="Borderless"
variant="borderless"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
</Flex>
<Flex gap={8}>
<Select
placeholder="Underlined"
variant="underlined"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
<Select
mode="multiple"
defaultValue={['lucy']}
placeholder="Underlined"
variant="underlined"
style={{ flex: 1 }}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
]}
/>
</Flex>
</Flex>
);
export default App;
커스텀 태그 렌더링 (Custom Tag Render)
태그를 커스텀 렌더링할 수 있습니다.
import React from 'react';
import { Select, Tag } from 'antd';
import type { SelectProps } from 'antd';
type TagRender = SelectProps['tagRender'];
const options: SelectProps['options'] = [
{ value: 'gold' },
{ value: 'lime' },
{ value: 'green' },
{ value: 'cyan' },
];
const tagRender: TagRender = (props) => {
const { label, value, closable, onClose } = props;
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
event.preventDefault();
event.stopPropagation();
};
return (
<Tag
color={value}
onMouseDown={onPreventMouseDown}
closable={closable}
onClose={onClose}
style={{ marginInlineEnd: 4 }}
>
{label}
</Tag>
);
};
const App: React.FC = () => (
<Select
mode="multiple"
tagRender={tagRender}
defaultValue={['gold', 'cyan']}
style={{ width: '100%' }}
options={options}
/>
);
export default App;
커스텀 선택 라벨 렌더링 (Custom Selected Label Render)
현재 선택된 라벨을 커스텀 렌더링할 수 있습니다. 값 백필(value backfill)이 필요하지만 해당 옵션이 없어서 값을 직접 렌더링하고 싶지 않을 때 사용할 수 있습니다.
import React from 'react';
import { Select } from 'antd';
import type { SelectProps } from 'antd';
type LabelRender = SelectProps['labelRender'];
const options = [
{ label: 'gold', value: 'gold' },
{ label: 'lime', value: 'lime' },
{ label: 'green', value: 'green' },
{ label: 'cyan', value: 'cyan' },
];
const labelRender: LabelRender = (props) => {
const { label, value } = props;
if (label) {
return value;
}
return <span>No option match</span>;
};
const App: React.FC = () => (
<Select labelRender={labelRender} defaultValue="1" style={{ width: '100%' }} options={options} />
);
export default App;
반응형 maxTagCount (Responsive maxTagCount)
반응형 상황에서 자동으로 태그를 접습니다. 반응형 계산에 성능 비용이 들기 때문에 대규모 폼에서는 권장하지 않습니다.
import React, { useState } from 'react';
import type { SelectProps } from 'antd';
import { Select, Space, Tooltip } from 'antd';
interface ItemProps {
label: string;
value: string;
}
const options: ItemProps[] = [];
for (let i = 10; i < 36; i++) {
const value = i.toString(36) + i;
options.push({
label: `Long Label: ${value}`,
value,
});
}
const sharedProps: SelectProps = {
mode: 'multiple',
style: { width: '100%' },
options,
placeholder: 'Select Item...',
maxTagCount: 'responsive',
};
const App: React.FC = () => {
const [value, setValue] = useState(['a10', 'c12', 'h17', 'j19', 'k20']);
const selectProps: SelectProps = {
value,
onChange: setValue,
};
return (
<Space vertical style={{ width: '100%' }}>
<Select {...sharedProps} {...selectProps} />
<Select {...sharedProps} disabled />
<Select
{...sharedProps}
{...selectProps}
maxTagPlaceholder={(omittedValues) => (
<Tooltip
styles={{ root: { pointerEvents: 'none' } }}
title={omittedValues.map(({ label }) => label).join(', ')}
>
<span>Hover Me</span>
</Tooltip>
)}
/>
</Space>
);
};
export default App;
빅 데이터 (Big Data)
Select는 가상 스크롤을 사용해 더 나은 성능을 제공하며, virtual={false}로 끌 수 있습니다.
import React from 'react';
import type { SelectProps } from 'antd';
import { Select, Typography } from 'antd';
const { Title } = Typography;
const options: SelectProps['options'] = [];
for (let i = 0; i < 100000; i++) {
const value = `${i.toString(36)}${i}`;
options.push({
label: value,
value,
disabled: i === 10,
});
}
const handleChange = (value: string[]) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<>
<Title level={4}>{options.length} Items</Title>
<Select
mode="multiple"
style={{ width: '100%' }}
placeholder="Please select"
defaultValue={['a10', 'c12']}
onChange={handleChange}
options={options}
/>
</>
);
export default App;
상태 (Status)
status로 Select에 상태를 추가합니다. error 또는 warning이 될 수 있습니다.
import React from 'react';
import { Select, Space } from 'antd';
const App: React.FC = () => (
<Space vertical style={{ width: '100%' }}>
<Select status="error" style={{ width: '100%' }} />
<Select status="warning" style={{ width: '100%' }} />
</Space>
);
export default App;
배치 (Placement)
placement로 팝업의 위치를 직접 지정할 수 있습니다.
import React, { useState } from 'react';
import type { RadioChangeEvent, SelectProps } from 'antd';
import { Radio, Select } from 'antd';
type SelectCommonPlacement = SelectProps['placement'];
const App: React.FC = () => {
const [placement, setPlacement] = useState<SelectCommonPlacement>('topLeft');
const placementChange = (e: RadioChangeEvent) => {
setPlacement(e.target.value);
};
return (
<>
<Radio.Group value={placement} onChange={placementChange}>
<Radio.Button value="topLeft">topLeft</Radio.Button>
<Radio.Button value="topRight">topRight</Radio.Button>
<Radio.Button value="bottomLeft">bottomLeft</Radio.Button>
<Radio.Button value="bottomRight">bottomRight</Radio.Button>
</Radio.Group>
<br />
<br />
<Select
defaultValue="HangZhou"
style={{ width: 120 }}
popupMatchSelectWidth={false}
placement={placement}
options={[
{
value: 'HangZhou',
label: 'HangZhou #310000',
},
{
value: 'NingBo',
label: 'NingBo #315000',
},
{
value: 'WenZhou',
label: 'WenZhou #325000',
},
]}
/>
</>
);
};
export default App;
최대 개수 (Max Count)
maxCount prop으로 선택할 수 있는 최대 항목 수를 제어할 수 있습니다. 한도를 초과하면 옵션들이 비활성화됩니다.
import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import { Select } from 'antd';
const MAX_COUNT = 3;
const App: React.FC = () => {
const [value, setValue] = React.useState<string[]>(['Ava Swift']);
const suffix = (
<>
<span>
{value.length} / {MAX_COUNT}
</span>
<DownOutlined />
</>
);
return (
<Select
mode="multiple"
maxCount={MAX_COUNT}
value={value}
style={{ width: '100%' }}
onChange={setValue}
suffixIcon={suffix}
placeholder="Please select"
options={[
{ value: 'Ava Swift', label: 'Ava Swift' },
{ value: 'Cole Reed', label: 'Cole Reed' },
{ value: 'Mia Blake', label: 'Mia Blake' },
{ value: 'Jake Stone', label: 'Jake Stone' },
{ value: 'Lily Lane', label: 'Lily Lane' },
{ value: 'Ryan Chase', label: 'Ryan Chase' },
{ value: 'Zoe Fox', label: 'Zoe Fox' },
{ value: 'Alex Grey', label: 'Alex Grey' },
{ value: 'Elle Blair', label: 'Elle Blair' },
]}
/>
);
};
export default App;
커스텀 시맨틱 DOM 스타일링 (Custom semantic dom styling)
classNames와 styles에 객체 또는 함수를 넘겨서 Select의 시맨틱 DOM 스타일을 커스터마이즈할 수 있습니다.
import React from 'react';
import { MehOutlined } from '@ant-design/icons';
import { Flex, Select } from 'antd';
import type { GetProp, SelectProps } from 'antd';
import { createStaticStyles } from 'antd-style';
const classNames = createStaticStyles(({ css }) => ({
root: css`
border-radius: 8px;
width: 300px;
`,
}));
const options: SelectProps['options'] = [
{ value: 'GuangZhou', label: 'GuangZhou' },
{ value: 'ShenZhen', label: 'ShenZhen' },
];
const stylesObject: SelectProps['styles'] = {
prefix: {
color: '#1890ff',
},
suffix: {
color: '#1890ff',
},
};
const stylesFn: SelectProps['styles'] = ({ props }): GetProp<SelectProps, 'styles', 'Return'> => {
if (props.variant === 'filled') {
return {
prefix: {
color: '#722ed1',
},
suffix: {
color: '#722ed1',
},
popup: {
root: {
border: '1px solid #722ed1',
},
},
};
}
return {};
};
const App: React.FC = () => {
const sharedProps: SelectProps = {
options,
classNames,
prefix: <MehOutlined />,
};
return (
<Flex vertical gap="medium">
<Select {...sharedProps} styles={stylesObject} placeholder="Object" />
<Select {...sharedProps} styles={stylesFn} placeholder="Function" variant="filled" />
</Flex>
);
};
export default App;
API
Common props ref:Common props
Select props
| Property | Description | Type | Default | Version | Global Config |
|---|---|---|---|---|---|
| allowClear | Customize clear icon | boolean | { clearIcon?: ReactNode } | false | 5.8.0: Support object type | 6.4.0 |
Whether the current search will be cleared on selecting an item. Only applies when mode is set to multiple or tags |
boolean | true | × | ||
Whether has border style, please use variant instead |
boolean | true | - | × | |
| classNames | Customize class for each semantic structure inside the Select component. Supports object or function. | Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> | - | 5.25.0 | |
| defaultActiveFirstOption | Whether active first option by default | boolean | true | × | |
| defaultOpen | Initial open state of dropdown | boolean | - | × | |
| defaultValue | Initial selected option | string | string[] | number | number[] | LabeledValue | LabeledValue[] |
- | × | |
| disabled | Whether disabled select | boolean | false | × | |
The className of dropdown menu, please use classNames.popup.root instead |
string | - | - | × | |
Determine whether the popup menu and the select input are the same width, please use popupMatchSelectWidth instead |
boolean | number | true | - | × | |
The className of dropdown menu, use classNames.popup.root instead |
string | - | 4.23.0 | × | |
| popupMatchSelectWidth | Determine whether the popup menu and the select input are the same width. Default set min-width same as input. Will ignore when value less than select width. false will disable virtual scroll |
boolean | number | true | 5.5.0 | × |
Customize dropdown content, use popupRender instead |
(originNode: ReactElement) => ReactNode | - | × | ||
| popupRender | Customize dropdown content | (originNode: ReactElement) => ReactNode | - | 5.25.0 | × |
The style of dropdown menu, use styles.popup.root instead |
CSSProperties | - | × | ||
| fieldNames | Customize node label, value, options,groupLabel field name | object | { label: label, value: value, options: options, groupLabel: label } |
4.17.0 (groupLabel added in 5.6.0) |
× |
If true, filter options by input, if function, filter options against it. The function will receive two arguments, inputValue and option, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded |
boolean | function(inputValue, option) | true | × | ||
| Sort function for search options sorting, see Array.sort's compareFunction | (optionA: Option, optionB: Option, info: { searchValue: string }) => number | - | searchValue: 5.19.0 |
× | |
| getPopupContainer | Parent Node which the selector should be rendered to. Default to body. When position issues happen, try to modify it into scrollable content and position it relative. Example |
function(triggerNode) | () => document.body | × | |
| labelInValue | Whether to embed label in value, turn the format of value from string to { value: string, label: ReactNode } |
boolean | false | × | |
| listHeight | Config popup height | number | 256 | × | |
| loading | Indicate loading state | boolean | false | × | |
| loadingIcon | Customize the loading icon | ReactNode | <LoadingOutlined spin /> |
6.4.0 | 6.4.0 |
| maxCount | The max number of items can be selected, only applies when mode is multiple or tags |
number | - | 5.13.0 | × |
| maxTagCount | Max tag count to show. responsive will cost render performance |
number | responsive |
- | responsive: 4.10 | × |
| maxTagPlaceholder | Placeholder for not showing tags | ReactNode | function(omittedValues) | - | × | |
| maxTagTextLength | Max tag text length to show | number | - | × | |
| menuItemSelectedIcon | The custom menuItemSelected icon with multiple options | ReactNode | <CheckOutlined /> |
6.4.0 | |
| mode | Set mode of Select | multiple | tags |
- | × | |
| notFoundContent | Specify content to show when no result matches | ReactNode | No data |
× | |
| open | Controlled open state of dropdown | boolean | - | × | |
Deprecated, see showSearch.optionFilterProp |
× | ||||
| optionLabelProp | Which prop value of option will render as content of select. Example | string | children |
× | |
| options | Select options. Will get better perf than jsx definition | { label, value }[] | - | × | |
| optionRender | Customize the rendering dropdown options | (option: FlattenOptionData<BaseOptionType> , info: { index: number }) => React.ReactNode | - | 5.11.0 | × |
| placeholder | Placeholder of select | ReactNode | - | × | |
| placement | The position where the selection box pops up | bottomLeft bottomRight topLeft topRight |
bottomLeft | × | |
| prefix | The custom prefix | ReactNode | - | 5.22.0 | × |
| removeIcon | The custom remove icon | ReactNode | <CloseOutlined /> |
6.4.0 | |
| The current input "search" text | string | - | × | ||
Whether to show the arrow icon, please use suffixIcon={null} instead |
boolean | true | - | × | |
| showSearch | Whether select is searchable | boolean | Object | single: false, multiple: true | Object: 6.0.0 | 6.4.0 |
| size | Size of Select input | large | medium | small |
medium |
× | |
| status | Set validation status | 'error' | 'warning' | - | 4.19.0 | × |
| styles | Customize inline style for each semantic structure inside the Select component. Supports object or function. | Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> | - | 5.25.0 | |
| suffixIcon | The custom suffix icon. Custom icons will not respond to clicks to open, because the replaced icon may be designed for other interactions. You can use pointer-events: none style to bypass |
ReactNode | <DownOutlined /> |
6.4.0 | |
| tagRender | Customize tag render, only applies when mode is set to multiple or tags |
(props) => ReactNode | - | × | |
| labelRender | Customize selected label render (LabelInValueType definition see LabelInValueType) | (props: LabelInValueType) => ReactNode | - | 5.15.0 | × |
| tokenSeparators | Separator used to tokenize, only applies when mode="tags" or mode="multiple" |
string[] | ((input: string) => string[]) | - | function: 6.5.0 | × |
| value | Current selected option (considered as a immutable array) | string | string[] | number | number[] | LabeledValue | LabeledValue[] |
- | × | |
| variant | Variants of selector | outlined | borderless | filled | underlined |
outlined |
5.13.0 | underlined: 5.24.0 |
5.19.0 |
| virtual | Disable virtual scroll when set to false | boolean | true | 4.1.0 | × |
| onActive | Called when keyboard or mouse interaction occurs | function(value: string | number | LabeledValue) | - | × | |
| onBlur | Called when blur | function | - | × | |
| onChange | Called when select an option or input value change | function(value, option:Option | Array<Option>) | - | × | |
| onClear | Called when clear | function | - | 4.6.0 | × |
| onDeselect | Called when an option is deselected, param is the selected option's value. Only called for multiple or tags, effective in multiple or tags mode only |
function(value: string | number | LabeledValue) | - | × | |
Called when dropdown open, use onOpenChange instead |
(open: boolean) => void | - | × | ||
| onOpenChange | Called when dropdown open | (open: boolean) => void | - | × | |
| onFocus | Called when focus | (event: FocusEvent) => void | - | × | |
| onInputKeyDown | Called when key pressed | (event: KeyboardEvent) => void | - | × | |
| onPopupScroll | Called when dropdown scrolls | (event: UIEvent) => void | - | × | |
| Callback function that is fired when input changed | function(value: string) | - | × | ||
| onSelect | Called when an option is selected, the params are option's value (or key) and option instance | function(value: string | number | LabeledValue, option: Option) | - | × |
참고: 드롭다운 메뉴가 페이지와 함께 스크롤되거나 다른 팝업 레이어에서 Select를 트리거해야 하는 경우,
getPopupContainer={triggerNode => triggerNode.parentElement}를 사용해 드롭다운 팝업 렌더링 노드를 트리거의 부모 요소에 고정해 보세요.
showSearch
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
| autoClearSearchValue | Whether the current search will be cleared on selecting an item. Only applies when mode is set to multiple or tags |
boolean | true | |
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, inputValue and option, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded |
boolean | function(inputValue, option) | true | |
| filterSort | Sort function for search options sorting, see Array.sort's compareFunction | (optionA: Option, optionB: Option, info: { searchValue: string }) => number | - | searchValue: 5.19.0 |
| optionFilterProp | Which prop value of option will be used for filter if filterOption is true. If options is set, it should be set to label. When a string[] is provided, multiple fields are searched using OR matching. |
string | string[] | value |
string[]: 6.1.0 |
| searchValue | The current input "search" text | string | - | |
| onSearch | Callback function that is fired when input changed | function(value: string) | - | |
| searchIcon | Customize the search icon | ReactNode | <SearchOutlined /> |
6.4.0 |
Select 메서드 (Select Methods)
| Name | Description | Version |
|---|---|---|
| blur() | Remove focus | |
| focus() | Get focus |
Option props
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
| className | The additional class to option | string | - | |
| disabled | Disable this option | boolean | false | |
| title | title attribute of Select Option |
string | - | |
| value | Default to filter with this property | string | number | - |
OptGroup props
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
| key | Group key | string | - | |
| label | Group label | React.ReactNode | - | |
| className | The additional class to option | string | - | |
| title | title attribute of Select Option |
string | - |
시맨틱 DOM (Semantic DOM)
https://ant.design/components/select/semantic.md
디자인 토큰 (Design Token)
컴포넌트 토큰 (Component Token - Select)
| Token Name | Description | Type | Default Value |
|---|---|---|---|
| activeBorderColor | Active border color | string | #1677ff |
| activeOutlineColor | Active outline color | string | rgba(5,145,255,0.1) |
| clearBg | Background color of clear button | string | #ffffff |
| hoverBorderColor | Hover border color | string | #4096ff |
| multipleItemBg | Background color of multiple tag | string | rgba(0,0,0,0.06) |
| multipleItemBorderColor | Border color of multiple tag | string | transparent |
| multipleItemBorderColorDisabled | Border color of multiple tag when disabled | string | transparent |
| multipleItemColorDisabled | Text color of multiple tag when disabled | string | rgba(0,0,0,0.25) |
| multipleItemHeight | Height of multiple tag | number | 24 |
| multipleItemHeightLG | Height of multiple tag with large size | number | 32 |
| multipleItemHeightSM | Height of multiple tag with small size | number | 16 |
| multipleSelectorBgDisabled | Background color of multiple selector when disabled | string | rgba(0,0,0,0.04) |
| optionActiveBg | Background color when option is active | string | rgba(0,0,0,0.04) |
| optionFontSize | Font size of option | number | 14 |
| optionHeight | Height of option | number | 32 |
| optionLineHeight | Line height of option | LineHeight<string | number> | undefined | 1.5714285714285714 |
| optionPadding | Padding of option | Padding<string | number> | undefined | 5px 12px |
| optionSelectedBg | Background color when option is selected | string | #e6f4ff |
| optionSelectedColor | Text color when option is selected | string | rgba(0,0,0,0.88) |
| optionSelectedFontWeight | Font weight when option is selected | FontWeight | undefined | 600 |
| selectorBg | Background color of selector | string | #ffffff |
| showArrowPaddingInlineEnd | Inline end padding of arrow | number | 18 |
| singleItemHeightLG | Height of single selected item with large size | number | 40 |
| zIndexPopup | z-index of dropdown | number | 1050 |
글로벌 토큰 (Global Token)
| Token Name | Description | Type | Default Value |
|---|---|---|---|
| borderRadius | Border radius of base components | number | |
| borderRadiusLG | LG size border radius, used in some large border radius components, such as Card, Modal and other components. | number | |
| borderRadiusSM | SM size border radius, used in small size components, such as Button, Input, Select and other input components in small size | number | |
| borderRadiusXS | XS size border radius, used in some small border radius components, such as Segmented, Arrow and other components with small border radius. | number | |
| boxShadowSecondary | Control the secondary box shadow style of an element. | string | |
| colorBgContainer | Container background color, e.g: default button, input box, etc. Be sure not to confuse this with colorBgElevated. |
string | |
| colorBgContainerDisabled | Control the background color of container in disabled state. | string | |
| colorBgElevated | Container background color of the popup layer, in dark mode the color value of this token will be a little brighter than colorBgContainer. E.g: modal, pop-up, menu, etc. |
string | |
| colorBorder | Default border color, used to separate different elements, such as: form separator, card separator, etc. | string | |
| colorBorderDisabled | Control the border color of the element in the disabled state. | string | |
| colorError | Used to represent the visual elements of the operation failure, such as the error Button, error Result component, etc. | string | |
| colorErrorAffix | Control the color of form control prefix/suffix in error state. | string | |
| colorErrorBg | The background color of the error state. | string | |
| colorErrorBgHover | The hover state background color of the error state. | string | |
| colorErrorBorderHover | The hover state border color of the error state. | string | |
| colorErrorOutline | Control the outline color of input component in error state. | string | |
| colorErrorText | The default state of the text in the error color. | string | |
| colorFillQuaternary | The weakest level of fill color is suitable for color blocks that are not easy to attract attention, such as zebra stripes, color blocks that distinguish boundaries, etc. | string | |
| colorFillSecondary | The second level of fill color can outline the shape of the element more clearly, such as Rate, Skeleton, etc. It can also be used as the Hover state of the third level of fill color, such as Table, etc. | string | |
| colorFillTertiary | The third level of fill color is used to outline the shape of the element, such as Slider, Segmented, etc. If there is no emphasis requirement, it is recommended to use the third level of fill color as the default fill color. | string | |
| colorIcon | Weak action. Such as allowClear or Alert close button |
string | |
| colorIconHover | Weak action hover color. Such as allowClear or Alert close button |
string | |
| colorPrimary | Brand color is one of the most direct visual elements to reflect the characteristics and communication of the product. After you have selected the brand color, we will automatically generate a complete color palette and assign it effective design semantics. | string | |
| colorSplit | Used as the color of separator, this color is the same as colorBorderSecondary but with transparency. | string | |
| colorText | Default text color which comply with W3C standards, and this color is also the darkest neutral color. | string | |
| colorTextDescription | Control the font color of text description. | string | |
| colorTextDisabled | Control the color of text in disabled state. | string | |
| colorTextPlaceholder | Control the color of placeholder text. | string | |
| colorTextQuaternary | The fourth level of text color is the lightest text color, such as form input prompt text, disabled color text, etc. | string | |
| colorWarning | Used to represent the warning map token, such as Notification, Alert, etc. Alert or Control component(like Input) will use these map tokens. | string | |
| colorWarningAffix | Control the color of form control prefix/suffix in warning state. | string | |
| colorWarningBg | The background color of the warning state. | string | |
| colorWarningBgHover | The hover state background color of the warning state. | string | |
| colorWarningHover | The hover state of the warning color. | string | |
| colorWarningOutline | Control the outline color of input component in warning state. | string | |
| controlHeight | The height of the basic controls such as buttons and input boxes in Ant Design | number | |
| controlHeightLG | LG component height | number | |
| controlHeightSM | SM component height | number | |
| controlItemBgActiveHover | Control the background color of control component item when hovering and active. | string | |
| controlOutlineWidth | Control the outline width of input component. | number | |
| controlPaddingHorizontal | Control the horizontal padding of an element. | number | |
| fontFamily | The font family of Ant Design prioritizes the default interface font of the system, and provides a set of alternative font libraries that are suitable for screen display to maintain the readability and readability of the font under different platforms and browsers, reflecting the friendly, stable and professional characteristics. | string | |
| fontSize | The most widely used font size in the design system, from which the text gradient will be derived. | number | |
| fontSizeIcon | Control the font size of operation icon in Select, Cascader, etc. Normally same as fontSizeSM. | number | |
| fontSizeLG | Large font size | number | |
| fontSizeSM | Small font size | number | |
| lineHeight | Line height of text. | number | |
| lineHeightLG | Line height of large text. | number | |
| lineType | Border style of base components | string | |
| lineWidth | Border width of base components | number | |
| marginXS | Control the margin of an element, with a small size. | number | |
| motionDurationMid | Motion speed, medium speed. Used for medium element animation interaction. | string | |
| motionDurationSlow | Motion speed, slow speed. Used for large element animation interaction. | string | |
| motionEaseInOut | Preset motion curve. | string | |
| motionEaseInOutCirc | Preset motion curve. | string | |
| motionEaseInQuint | Preset motion curve. | string | |
| motionEaseOutCirc | Preset motion curve. | string | |
| motionEaseOutQuint | Preset motion curve. | string | |
| paddingSM | Control the small padding of the element. | number | |
| paddingXS | Control the extra small padding of the element. | number | |
| paddingXXS | Control the extra extra small padding of the element. | number |
FAQ
tags 모드에서 검색할 때 같은 옵션이 2개 나오는 경우가 있습니다. 왜 그런가요? {#faq-tags-mode-duplicate}
label과 value가 다른 옵션 때문에 발생합니다. 대신 optionFilterProp="label"을 사용해 필터 로직을 바꿀 수 있습니다.
popupRender에서 요소를 클릭하면 select 드롭다운이 닫히지 않는 경우가 있습니다. 어떻게 하나요? {#faq-popup-not-close}
open prop으로 제어할 수 있습니다: codesandbox.
popupRender 안을 클릭했을 때 드롭다운이 닫히지 않았으면 합니다. 어떻게 하나요? {#faq-popup-keep-open}
Select는 포커스를 잃으면 닫힙니다. 이벤트를 막아 처리할 수 있습니다:
<Select
popupRender={() => (
<div
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
Some Content
</div>
)}
/>
커스텀 Option이 스크롤 깨짐을 일으키는 이유는 무엇인가요? {#faq-custom-option-scroll}
가상 스크롤은 내부적으로 항목 높이를 24px로 설정합니다. 옵션 높이가 더 작다면 listItemHeight를, 리스트 컨테이너 높이는 listHeight로 조정해야 합니다:
<Select listItemHeight={10} listHeight={250} />
참고: listItemHeight와 listHeight는 내부 prop입니다. 필요한 경우에만 수정하세요.
a11y 테스트 보고서에 aria- props가 빠져 있다고 나오는 이유는 무엇인가요? {#faq-aria-attribute}
Select는 작동할 때만 a11y 보조 노드를 생성합니다. Select를 열고 다시 시도하세요. aria-label 및 aria-labelledby 경고 누락의 경우, 자신의 요구에 맞게 Select에 관련 prop을 추가해 주세요.
기본 가상 스크롤은 접근 가능한 바인딩을 시뮬레이션하는 mock 요소를 생성합니다. 스크린 리더가 전체 리스트에 완전히 접근해야 한다면 virtual={false}로 가상 스크롤을 비활성화하면 접근성 옵션이 실제 요소에 바인딩됩니다.
커스텀 tagRender 태그에서 닫기 클릭 시 드롭다운이 열리는 이유는 무엇인가요? {#faq-tagrender-dropdown}
(닫기 아이콘 같은) 요소를 클릭한 뒤 드롭다운 메뉴가 자동으로 나타나지 않게 하려면 요소에서 MouseDown 이벤트의 전파를 막을 수 있습니다.
<Select
tagRender={(props) => {
const { closable, label, onClose } = props;
return (
<span className="border">
{label}
{closable ? (
<span
onMouseDown={(e) => e.stopPropagation()}
onClick={onClose}
className="cursor-pointer"
>
❎
</span>
) : null}
</span>
);
}}
/>