logoMogu Design

⌘ K
  • 设计
  • 研发
  • 组件
  • 组件总览
  • 通用
    • Button按钮
    • Icon图标
    • Typography排版
  • 布局
    • Divider分割线
    • Grid栅格
    • Layout布局
    • Space间距
  • 导航
    • Anchor锚点
    • Breadcrumb面包屑
    • Dropdown下拉菜单
    • Menu导航菜单
    • Pagination分页
    • Steps步骤条
  • 数据录入
    • AutoComplete自动完成
    • Cascader级联选择
    • Checkbox多选框
    • ColorPicker颜色选择器New
    • DatePicker日期选择框
    • Form表单
    • Input输入框
    • InputNumber数字输入框
    • Mentions提及
    • Radio单选框
    • Rate评分
    • Select选择器
    • Slider滑动输入条
    • Switch开关
    • TimePicker时间选择框
    • Transfer穿梭框
    • TreeSelect树选择
    • Upload上传
  • 数据展示
    • Avatar头像
    • Badge徽标数
    • Calendar日历
    • Card卡片
    • Carousel走马灯
    • Collapse折叠面板
    • Descriptions描述列表
    • Empty空状态
    • Image图片
    • List列表
    • Popover气泡卡片
    • QRCode二维码
    • Segmented分段控制器
    • Statistic统计数值
    • Table表格
    • Tabs标签页
    • Tag标签
    • Timeline时间轴
    • Tooltip文字提示
    • Tour漫游式引导
    • Tree树形控件
  • 反馈
    • Alert警告提示
    • Drawer抽屉
    • Message全局提示
    • Modal对话框
    • Notification通知提醒框
    • Popconfirm气泡确认框
    • Progress进度条
    • Result结果
    • Skeleton骨架屏
    • Spin加载中
  • 其他
    • Affix固钉
    • App包裹组件
    • ConfigProvider全局化配置
    • FloatButton悬浮按钮
    • Watermark水印
何时使用
代码演示
基本使用
带搜索框
多选
三种大小
定制回填内容
带排序的搜索
标签
分组
联动
搜索框
获得选项的文本
自动分词
搜索用户
扩展菜单
隐藏已选择选项
无边框
自定义选择标签
响应式 maxTagCount
大数据
自定义状态
弹出位置
API
Select props
Select Methods
Option props
OptGroup props
Design Token
FAQ
mode="tags" 模式下为何搜索有时会出现两个相同选项?
点击 dropdownRender 里的元素,下拉菜单不会自动消失?
反过来希望点击 dropdownRender 里元素不消失该怎么办?
自定义 Option 样式导致滚动异常怎么办?
为何无障碍测试会报缺失 aria- 属性?

Select选择器

Rate评分Slider滑动输入条

下拉选择器。

何时使用

  • 弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。
  • 当选项少时(少于 5 项),建议直接将选项平铺,使用 Radio 是更好的选择。

代码演示

Lucy
Lucy
Lucy
Lucy
基本使用

基本使用。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select, Space } from 'mogud';

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' }]}
    />
  </Space>
);

export default App;
a10
c12
 
a10
c12
 
多选

多选,从已有条目中选择。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select, Space } from 'mogud';
import type { SelectProps } from 'mogud';

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%' }} direction="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;
China
 
定制回填内容

使用 optionLabelProp 指定回填到选择框的 Option 属性。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select, Space } from 'mogud';

const { Option } = Select;

const handleChange = (value: string[]) => {
  console.log(`selected ${value}`);
};

const App: React.FC = () => (
  <Select
    mode="multiple"
    style={{ width: '100%' }}
    placeholder="select one country"
    defaultValue={['china']}
    onChange={handleChange}
    optionLabelProp="label"
  >
    <Option value="china" label="China">
      <Space>
        <span role="img" aria-label="China">
          🇨🇳
        </span>
        China (中国)
      </Space>
    </Option>
    <Option value="usa" label="USA">
      <Space>
        <span role="img" aria-label="USA">
          🇺🇸
        </span>
        USA (美国)
      </Space>
    </Option>
    <Option value="japan" label="Japan">
      <Space>
        <span role="img" aria-label="Japan">
          🇯🇵
        </span>
        Japan (日本)
      </Space>
    </Option>
    <Option value="korea" label="Korea">
      <Space>
        <span role="img" aria-label="Korea">
          🇰🇷
        </span>
        Korea (韩国)
      </Space>
    </Option>
  </Select>
);

export default App;
 
Tags Mode
标签

tags select,随意输入的内容(scroll the menu)。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select } from 'mogud';
import type { SelectProps } from 'mogud';

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;
Zhejiang
Hangzhou
联动

省市联动是典型的例子。

推荐使用 Cascader 组件。

expand codeexpand code
TypeScript
JavaScript
import React, { useState } from 'react';
import { Select, Space } from 'mogud';

const provinceData = ['Zhejiang', 'Jiangsu'];

const cityData = {
  Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],
  Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang'],
};

type CityName = keyof typeof cityData;

const App: React.FC = () => {
  const [cities, setCities] = useState(cityData[provinceData[0] as CityName]);
  const [secondCity, setSecondCity] = useState(cityData[provinceData[0] as CityName][0]);

  const handleProvinceChange = (value: CityName) => {
    setCities(cityData[value]);
    setSecondCity(cityData[value][0]);
  };

  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;
Lucy (101)
获得选项的文本

默认情况下 onChange 里只能拿到 value,如果需要拿到选中的节点文本 label,可以使用 labelInValue 属性。

选中项的 label 会被包装到 value 中传递给 onChange 等函数,此时 value 是一个对象。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select } from 'mogud';

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;
 
Select users
搜索用户

一个带有远程搜索,防抖控制,请求时序控制,加载状态的多选示例。

expand codeexpand code
TypeScript
JavaScript
import React, { useMemo, useRef, useState } from 'react';
import { Select, Spin } from 'mogud';
import type { SelectProps } from 'mogud/es/select';
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 } = any,
>({ fetchOptions, debounceTimeout = 800, ...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
      filterOption={false}
      onSearch={debounceFetcher}
      notFoundContent={fetching ? <Spin size="small" /> : null}
      {...props}
      options={options}
    />
  );
}

// Usage of DebounceSelect
interface UserValue {
  label: string;
  value: string;
}

async function fetchUserList(username: string): Promise<UserValue[]> {
  console.log('fetching user', username);

  return fetch('https://randomuser.me/api/?results=5')
    .then((response) => response.json())
    .then((body) =>
      body.results.map(
        (user: { name: { first: string; last: string }; login: { username: string } }) => ({
          label: `${user.name.first} ${user.name.last}`,
          value: user.login.username,
        }),
      ),
    );
}

const App: React.FC = () => {
  const [value, setValue] = useState<UserValue[]>([]);

  return (
    <DebounceSelect
      mode="multiple"
      value={value}
      placeholder="Select users"
      fetchOptions={fetchUserList}
      onChange={(newValue) => {
        setValue(newValue as UserValue[]);
      }}
      style={{ width: '100%' }}
    />
  );
};

export default App;
 
Inserted are removed
隐藏已选择选项

隐藏下拉列表中已选择的选项。

expand codeexpand code
TypeScript
JavaScript
import React, { useState } from 'react';
import { Select } from 'mogud';

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;
gold
cyan
 
自定义选择标签

允许自定义选择标签的样式。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select, Tag } from 'mogud';
import type { CustomTagProps } from 'rc-select/lib/BaseSelect';

const options = [{ value: 'gold' }, { value: 'lime' }, { value: 'green' }, { value: 'cyan' }];

const tagRender = (props: CustomTagProps) => {
  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={{ marginRight: 3 }}
    >
      {label}
    </Tag>
  );
};

const App: React.FC = () => (
  <Select
    mode="multiple"
    showArrow
    tagRender={tagRender}
    defaultValue={['gold', 'cyan']}
    style={{ width: '100%' }}
    options={options}
  />
);

export default App;

Ant Design 4.0

100000 Items

a10
c12
 

Ant Design 3.0

大数据

Select 使用了虚拟滚动技术,因而获得了比 3.0 更好的性能。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import type { SelectProps } from 'mogud';
import { Divider, Select, Typography } from 'mogud';

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={3}>Ant Design 4.0</Title>
    <Title level={4}>{options.length} Items</Title>
    <Select
      mode="multiple"
      style={{ width: '100%' }}
      placeholder="Please select"
      defaultValue={['a10', 'c12']}
      onChange={handleChange}
      options={options}
    />

    <Divider />

    <Title level={3}>Ant Design 3.0</Title>
    <iframe
      title="Ant Design 3.0 Select demo"
      src="https://codesandbox.io/embed/solitary-voice-m3vme?fontsize=14&hidenavigation=1&theme=dark&view=preview"
      style={{ width: '100%', height: 300 }}
    />
  </>
);

export default App;


HangZhou #310000
弹出位置

可以通过 placement 手动指定弹出的位置。

expand codeexpand code
TypeScript
JavaScript
import React, { useState } from 'react';
import type { RadioChangeEvent } from 'mogud';
import { Radio, Select } from 'mogud';
import type { SelectCommonPlacement } from 'mogud/es/_util/motion';

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 }}
        dropdownMatchSelectWidth={false}
        placement={placement}
        options={[
          {
            value: 'HangZhou',
            label: 'HangZhou #310000',
          },
          {
            value: 'NingBo',
            label: 'NingBo #315000',
          },
          {
            value: 'WenZhou',
            label: 'WenZhou #325000',
          },
        ]}
      />
    </>
  );
};

export default App;
Select a person
带搜索框

展开后可对选项进行搜索。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select } from 'mogud';

const onChange = (value: string) => {
  console.log(`selected ${value}`);
};

const onSearch = (value: string) => {
  console.log('search:', value);
};

const App: React.FC = () => (
  <Select
    showSearch
    placeholder="Select a person"
    optionFilterProp="children"
    onChange={onChange}
    onSearch={onSearch}
    filterOption={(input, option) =>
      (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
    }
    options={[
      {
        value: 'jack',
        label: 'Jack',
      },
      {
        value: 'lucy',
        label: 'Lucy',
      },
      {
        value: 'tom',
        label: 'Tom',
      },
    ]}
  />
);

export default App;


a1
a10
c12
 
a10
c12
 
三种大小

三种大小的选择框,当 size 分别为 large 和 small 时,输入框高度为 40px 和 24px ,默认高度为 32px。

expand codeexpand code
TypeScript
JavaScript
import React, { useState } from 'react';
import { Radio, Select, Space } from 'mogud';
import type { SizeType } from 'mogud/es/config-provider/SizeContext';
import type { SelectProps, RadioChangeEvent } from 'mogud';

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>('middle');

  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="middle">Default</Radio.Button>
        <Radio.Button value="small">Small</Radio.Button>
      </Radio.Group>
      <br />
      <br />
      <Space direction="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;
Search to Select
带排序的搜索

在搜索模式下对过滤结果项进行排序。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select } from 'mogud';

const App: React.FC = () => (
  <Select
    showSearch
    style={{ width: 200 }}
    placeholder="Search to Select"
    optionFilterProp="children"
    filterOption={(input, option) => (option?.label ?? '').includes(input)}
    filterSort={(optionA, optionB) =>
      (optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase())
    }
    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;
Lucy
分组

用 OptGroup 进行选项分组。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select } from 'mogud';

const handleChange = (value: string) => {
  console.log(`selected ${value}`);
};

const App: React.FC = () => (
  <Select
    defaultValue="lucy"
    style={{ width: 200 }}
    onChange={handleChange}
    options={[
      {
        label: 'Manager',
        options: [
          { label: 'Jack', value: 'jack' },
          { label: 'Lucy', value: 'lucy' },
        ],
      },
      {
        label: 'Engineer',
        options: [{ label: 'yiminghe', value: 'Yiminghe' }],
      },
    ]}
  />
);

export default App;
input search text
搜索框

搜索和远程数据结合。

expand codeexpand code
TypeScript
JavaScript
import React, { useState } from 'react';
import { Select } from 'mogud';
import jsonp from 'fetch-jsonp';
import qs from 'qs';
import type { SelectProps } from 'mogud';

let timeout: ReturnType<typeof setTimeout> | null;
let currentValue: string;

const fetch = (value: string, callback: Function) => {
  if (timeout) {
    clearTimeout(timeout);
    timeout = null;
  }
  currentValue = value;

  const fake = () => {
    const str = qs.stringify({
      code: 'utf-8',
      q: value,
    });
    jsonp(`https://suggest.taobao.com/sug?${str}`)
      .then((response: any) => response.json())
      .then((d: any) => {
        if (currentValue === value) {
          const { result } = d;
          const data = result.map((item: any) => ({
            value: item[0],
            text: item[0],
          }));
          callback(data);
        }
      });
  };

  timeout = setTimeout(fake, 300);
};

const SearchInput: React.FC<{ placeholder: string; style: React.CSSProperties }> = (props) => {
  const [data, setData] = useState<SelectProps['options']>([]);
  const [value, setValue] = useState<string>();

  const handleSearch = (newValue: string) => {
    if (newValue) {
      fetch(newValue, setData);
    } else {
      setData([]);
    }
  };

  const handleChange = (newValue: string) => {
    setValue(newValue);
  };

  return (
    <Select
      showSearch
      value={value}
      placeholder={props.placeholder}
      style={props.style}
      defaultActiveFirstOption={false}
      showArrow={false}
      filterOption={false}
      onSearch={handleSearch}
      onChange={handleChange}
      notFoundContent={null}
      options={(data || []).map((d) => ({
        value: d.value,
        label: d.text,
      }))}
    />
  );
};

const App: React.FC = () => <SearchInput placeholder="input search text" style={{ width: 200 }} />;

export default App;
 
自动分词

试下复制 露西,杰克 并粘贴到输入框里。只在 tags 和 multiple 模式下可用。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select } from 'mogud';
import type { SelectProps } from 'mogud';

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 dropdown render
扩展菜单

使用 dropdownRender 对下拉菜单进行自由扩展。如果希望点击自定义内容后关闭浮层,你需要使用受控模式自行控制(codesandbox)。

expand codeexpand code
TypeScript
JavaScript
import React, { useState, useRef } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import { Divider, Input, Select, Space, Button } from 'mogud';
import type { InputRef } from 'mogud';

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"
      dropdownRender={(menu) => (
        <>
          {menu}
          <Divider style={{ margin: '8px 0' }} />
          <Space style={{ padding: '0 8px 4px' }}>
            <Input
              placeholder="Please enter item"
              ref={inputRef}
              value={name}
              onChange={onNameChange}
            />
            <Button type="text" icon={<PlusOutlined />} onClick={addItem}>
              Add item
            </Button>
          </Space>
        </>
      )}
      options={items.map((item) => ({ label: item, value: item }))}
    />
  );
};

export default App;
Lucy
Lucy
无边框

无边框样式。

expand codeexpand code
TypeScript
JavaScript
import { Select, Space } from 'mogud';
import React from 'react';

const App: React.FC = () => (
  <Space wrap>
    <Select
      defaultValue="lucy"
      style={{ width: 120 }}
      bordered={false}
      options={[
        { value: 'jack', label: 'Jack' },
        { value: 'lucy', label: 'Lucy' },
        { value: 'Yiminghe', label: 'yiminghe' },
      ]}
    />
    <Select
      defaultValue="lucy"
      style={{ width: 120 }}
      disabled
      bordered={false}
      options={[{ value: 'lucy', label: 'Lucy' }]}
    />
  </Space>
);

export default App;
+ 4 ...
 
+ 4 ...
 
响应式 maxTagCount

多选下通过响应式布局让选项自动收缩。该功能对性能有所消耗,不推荐在大表单场景下使用。

expand codeexpand code
TypeScript
JavaScript
import React, { useState } from 'react';
import type { SelectProps } from 'mogud';
import { Select, Space } from 'mogud';

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 App: React.FC = () => {
  const [value, setValue] = useState(['a10', 'c12', 'h17', 'j19', 'k20']);

  const selectProps: SelectProps = {
    mode: 'multiple',
    style: { width: '100%' },
    value,
    options,
    onChange: (newValue: string[]) => {
      setValue(newValue);
    },
    placeholder: 'Select Item...',
    maxTagCount: 'responsive',
  };

  return (
    <Space direction="vertical" style={{ width: '100%' }}>
      <Select {...selectProps} />
      <Select {...selectProps} disabled />
    </Space>
  );
};

export default App;
自定义状态

使用 status 为 Select 添加状态,可选 error 或者 warning。

expand codeexpand code
TypeScript
JavaScript
import React from 'react';
import { Select, Space } from 'mogud';

const App: React.FC = () => (
  <Space direction="vertical" style={{ width: '100%' }}>
    <Select status="error" style={{ width: '100%' }} />
    <Select status="warning" style={{ width: '100%' }} />
  </Space>
);

export default App;

API

Select props

参数说明类型默认值版本
allowClear支持清除booleanfalse
autoClearSearchValue是否在选中项后清空搜索框,只在 mode 为 multiple 或 tags 时有效booleantrue
autoFocus默认获取焦点booleanfalse
bordered是否有边框booleantrue
clearIcon自定义的多选框清空图标ReactNode-
defaultActiveFirstOption是否默认高亮第一个选项booleantrue
defaultOpen是否默认展开下拉菜单boolean-
defaultValue指定默认选中的条目string | string[] |
number | number[] |
LabeledValue | LabeledValue[]
-
disabled是否禁用booleanfalse
popupClassName下拉菜单的 className 属性string-4.23.0
popupMatchSelectWidth下拉菜单和选择器同宽。默认将设置 min-width,当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动boolean | numbertrue5.5.0
dropdownRender自定义下拉框内容(originNode: ReactNode) => ReactNode-
dropdownStyle下拉菜单的 style 属性CSSProperties-
fieldNames自定义节点 label、value、options、groupLabel 的字段object{ label: label, value: value, options: options, groupLabel: label }4.17.0(groupLabel 在 5.6.0 新增)
filterOption是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 falseboolean | function(inputValue, option)true
filterSort搜索时对筛选结果项的排序函数, 类似Array.sort里的 compareFunction(optionA: Option, optionB: Option) => number-4.9.0
getPopupContainer菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。示例function(triggerNode)() => document.body
labelInValue是否把每个选项的 label 包装到 value 中,会把 Select 的 value 类型从 string 变为 { value: string, label: ReactNode } 的格式booleanfalse
listHeight设置弹窗滚动高度number256
loading加载中状态booleanfalse
maxTagCount最多显示多少个 tag,响应式模式会对性能产生损耗number | responsive-responsive: 4.10
maxTagPlaceholder隐藏 tag 时显示的内容ReactNode | function(omittedValues)-
maxTagTextLength最大显示的 tag 文本长度number-
menuItemSelectedIcon自定义多选时当前选中的条目图标ReactNode-
mode设置 Select 的模式为多选或标签multiple | tags-
notFoundContent当下拉列表为空时显示的内容ReactNodeNot Found
open是否展开下拉菜单boolean-
optionFilterProp搜索时过滤对应的 option 属性,如设置为 children 表示对内嵌内容进行搜索。若通过 options 属性配置选项内容,建议设置 optionFilterProp="label" 来对内容进行搜索。stringvalue
optionLabelProp回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 value。示例stringchildren
options数据化配置选项内容,相比 jsx 定义会获得更好的渲染性能{ label, value }[]-
placeholder选择框默认文本string-
placement选择框弹出的位置bottomLeft bottomRight topLeft topRightbottomLeft
removeIcon自定义的多选框清除图标ReactNode-
searchValue控制搜索文本string-
showArrow是否显示下拉小箭头boolean单选为 true,多选为 false
showSearch配置是否可搜索boolean单选为 false,多选为 true
size选择框大小large | middle | smallmiddle
status设置校验状态'error' | 'warning'-4.19.0
suffixIcon自定义的选择框后缀图标。以防止图标被用于其他交互,替换的图标默认不会响应展开、收缩事件,可以通过添加 pointer-events: none 样式透传。ReactNode-
tagRender自定义 tag 内容 render,仅在 mode 为 multiple 或 tags 时生效(props) => ReactNode-
tokenSeparators自动分词的分隔符,仅在 mode="tags" 时生效string[]-
value指定当前选中的条目,多选时为一个数组。(value 数组引用未变化时,Select 不会更新)string | string[] |
number | number[] |
LabeledValue | LabeledValue[]
-
virtual设置 false 时关闭虚拟滚动booleantrue4.1.0
onBlur失去焦点时回调function-
onChange选中 option,或 input 的 value 变化时,调用此函数function(value, option:Option | Array<Option>)-
onClear清除内容时回调function-4.6.0
onDeselect取消选中时调用,参数为选中项的 value (或 key) 值,仅在 multiple 或 tags 模式下生效function(value: string | number | LabeledValue)-
onDropdownVisibleChange展开下拉菜单的回调function(open)-
onFocus获得焦点时回调function-
onInputKeyDown按键按下时回调function-
onMouseEnter鼠标移入时回调function-
onMouseLeave鼠标移出时回调function-
onPopupScroll下拉列表滚动时的回调function-
onSearch文本框值变化时回调function(value: string)-
onSelect被选中时调用,参数为选中项的 value (或 key) 值function(value: string | number | LabeledValue, option: Option)-

注意,如果发现下拉菜单跟随页面滚动,或者需要在其他弹层中触发 Select,请尝试使用 getPopupContainer={triggerNode => triggerNode.parentElement} 将下拉弹层渲染节点固定在触发器的父元素中。

Select Methods

名称说明版本
blur()取消焦点
focus()获取焦点

Option props

参数说明类型默认值版本
classNameOption 器类名string-
disabled是否禁用booleanfalse
title选项上的原生 title 提示string-
value默认根据此属性值进行筛选string | number-

OptGroup props

参数说明类型默认值版本
keyKeystring-
label组名string | React.Element-

Design Token

Global Token

FAQ

mode="tags" 模式下为何搜索有时会出现两个相同选项?

这一般是 options 中的 label 和 value 不同导致的,你可以通过 optionFilterProp="label" 将过滤设置为展示值以避免这种情况。

点击 dropdownRender 里的元素,下拉菜单不会自动消失?

你可以使用受控模式,手动设置 open 属性:codesandbox。

反过来希望点击 dropdownRender 里元素不消失该怎么办?

Select 当失去焦点时会关闭下拉框,如果你可以通过阻止默认行为避免丢失焦点导致的关闭:

<Select
dropdownRender={() => (
<div
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
Some Content
</div>
)}
/>

自定义 Option 样式导致滚动异常怎么办?

这是由于虚拟滚动默认选项高度为 24px,如果你的选项高度小于该值则需要通过 listItemHeight 属性调整,而 listHeight 用于设置滚动容器高度:

<Select listItemHeight={10} listHeight={250} />

注意:listItemHeight 和 listHeight 为内部属性,如无必要,请勿修改该值。

为何无障碍测试会报缺失 aria- 属性?

Select 无障碍辅助元素仅在弹窗展开时创建,因而当你在进行无障碍检测时请先打开下拉后再进行测试。对于 aria-label 与 aria-labelledby 属性缺失警告,请自行为 Select 组件添加相应无障碍属性。

Select 虚拟滚动会模拟无障碍绑定元素。如果需要读屏器完整获取全部列表,你可以设置 virtual={false} 关闭虚拟滚动,无障碍选项将会绑定到真实元素上。