Browse Source

feat: select support search position (#2298)

pointhalo 1 year ago
parent
commit
b99504c402

+ 52 - 1
content/input/select/index-en-US.md

@@ -616,6 +616,52 @@ import { Select } from '@douyinfe/semi-ui';
 );
 ```
 
+
+### Search position
+The default search input is displayed on the Select Trigger. You can specify different positions through `searchPosition`, and you can choose `dropdown` or `trigger`. Available after `v2.61.0`  
+If you want to customize the placeholder of the Input search box in the dropdown, you can control it through `searchPlaceholder`  
+If the `searchPosition` is `trigger`, when `showClear=true`, clicking the clear button of the input will clear the selected items and the search text in the input at the same time   
+If the `searchPosition` is `dropdown`, when `showClear=true`, clicking the clear button of the trigger will clear the selected items,  clicking the clear button in the dropdown input will clear search text  
+
+
+```jsx live=true
+import React from 'react';
+import { Select } from '@douyinfe/semi-ui';
+
+() => (
+    <>
+        <Select
+            filter
+            searchPosition='dropdown'
+            style={{ width: 200 }}
+            defaultValue={'ulikecam'}
+        >
+            <Select.Option value="douyin">Douyin</Select.Option>
+            <Select.Option value="ulikecam">UlikeCam</Select.Option>
+            <Select.Option value="jianying">Capcut</Select.Option>
+            <Select.Option value="xigua">XiguaVideo</Select.Option>
+        </Select>
+        <br />
+        <br />
+        <Select
+            filter
+            searchPosition='dropdown'
+            multiple
+            style={{ width: 300 }}
+            defaultValue={['semi-1']}
+            autoClearSearchValue={false}
+        >
+            <Select.Option value="semi-0">Semi-0</Select.Option>
+            <Select.Option value="semi-1">Semi-1</Select.Option>
+            <Select.Option value="semi-2">Semi-2</Select.Option>
+            <Select.Option value="semi-3">Semi-3</Select.Option>
+            <Select.Option value="semi-4">Semi-4</Select.Option>
+        </Select>
+    </>
+);
+
+```
+
 ### Remote search
 
 A multi-select example with remote search, request debounce, loading status.
@@ -1168,6 +1214,8 @@ import { IconAppCenter, IconChevronDown } from '@douyinfe/semi-icons';
                 value={valList}
                 triggerRender={triggerRender}
                 optionList={list}
+                filter
+                searchPosition='dropdown'
                 onChange={value => setValList(value)}
                 multiple
                 style={{ width: 240 }}
@@ -1180,6 +1228,8 @@ import { IconAppCenter, IconChevronDown } from '@douyinfe/semi-icons';
                 onChange={value => setVal(value)}
                 triggerRender={triggerRender2}
                 optionList={list}
+                filter
+                searchPosition='dropdown'
                 style={{ width: 240, marginTop: 20, outline: 0 }}
             ></Select>
         </div>
@@ -1363,10 +1413,11 @@ import { Select, Checkbox } from '@douyinfe/semi-ui';
 | renderCreateItem | When allowCreate is true, you can customize the rendering of the creation label                                                                                                                                                                                                                                                                                    | function(inputValue: string) | InputValue => 'Create' + InputValue |
 | renderSelectedItem | Customize the rendering of selected tabs in the selection box                                                                                                                                                                                                                                                                                                      | function(option) |  |
 | restTagsPopoverProps | The configuration properties of the [Popover](/en-US/show/popover#API%20Reference)                                                                                                                                                                                                                                                                                 | PopoverProps | {} | 2.22.0 |
+| size | Size, optional value `default` / `small` / `large`   
+| searchPosition | When the filter is turned on, the search box is in the trigger by default. You can set it to 'dropdown' to put the search box at the top of the popup list.  | string | 'trigger' | 2.61.0
 | showArrow | Whether to show arrow icon                                                                                                                                                                                                                                                                                                                                         | boolean | true |
 | showClear | Whether to show the clear button                                                                                                                                                                                                                                                                                                                                   | boolean | false |
 | showRestTagsPopover | When the number of tags exceeds maxTagCount and hover reaches +N, whether to display the remaining content through Popover                                                                                                                                                                                                                                         | boolean | false | 2.22.0 |
-| size | Size, optional value `default` / `small` / `large`                                                                                                                                                                                                                                                                                                                 | string | 'default' |
 | spacing | Spacing between popup layer and trigger                                                                                                                                                                                                                                                                                                                            | number | 4 |
 | stopPropagation | Whether to prevent click events on the popup layer from bubbling                                                                                                                                                                                                                                                                                                   | boolean | true |  |
 | style | Inline Style                                                                                                                                                                                                                                                                                                                                                       | object |  |

+ 56 - 3
content/input/select/index.md

@@ -699,11 +699,58 @@ import { Select } from '@douyinfe/semi-ui';
 );
 ```
 
+### 搜索框位置
+默认搜索框展示于 Select 的 Trigger 触发器上。通过 `searchPosition` 可以指定不同的位置,可选 `dropdown`、`trigger`。 在 v2.61.0后提供
+若希望定制位于 dropdown 中的 Input 搜索框的 placeholder,可以通过 `searchPlaceholder` 控制  
+若 `searchPosition` 值为 `trigger`,当showClear=true 时,点击Trigger区域的清空按钮,将同时清空已选项以及搜索框中的文本  
+若 `searchPosition` 值为 `dropdown`,当showClear=true 时,点击Trigger区域清空按钮,仅清空已选项。点击搜索框中的清空按钮,仅清空搜索文本  
+
+```jsx live=true
+import React from 'react';
+import { Select } from '@douyinfe/semi-ui';
+
+() => (
+    <>
+        <Select
+            filter
+            searchPosition='dropdown'
+            style={{ width: 200 }}
+            defaultValue={'ulikecam'}
+            placeholder='我的搜索框在下拉菜单中'
+            searchPlaceholder="带搜索功能的单选"
+        >
+            <Select.Option value="douyin">抖音</Select.Option>
+            <Select.Option value="ulikecam">轻颜相机</Select.Option>
+            <Select.Option value="jianying">剪映</Select.Option>
+            <Select.Option value="xigua">西瓜视频</Select.Option>
+        </Select>
+        <br />
+        <br />
+        <Select
+            filter
+            searchPosition='dropdown'
+            multiple
+            style={{ width: 300 }}
+            defaultValue={['semi-1']}
+            placeholder='我的搜索框在下拉菜单中'
+            searchPlaceholder="带搜索功能的多选"
+            autoClearSearchValue={false}
+        >
+            <Select.Option value="semi-0">Semi-0</Select.Option>
+            <Select.Option value="semi-1">Semi-1</Select.Option>
+            <Select.Option value="semi-2">Semi-2</Select.Option>
+            <Select.Option value="semi-3">Semi-3</Select.Option>
+            <Select.Option value="semi-4">Semi-4</Select.Option>
+        </Select>
+    </>
+);
+```
+
 ### 远程搜索
 
 带有远程搜索,防抖请求,加载状态的多选示例  
 通过`filter`开启搜索能力  
-将`remote`设置为 true 关闭对当前数据的筛选过滤(在 v0.24.0 后提供)  
+将`remote`设置为 true 关闭对当前数据的筛选过滤
 通过动态更新`optionList`更新下拉菜单中的备选项  
 使用受控的 value 属性
 
@@ -1121,7 +1168,8 @@ class VirtualizeDemo extends React.Component {
 
 ### 自定义触发器
 
-如果 Select 默认的触发器样式满足不了你的需求,可以用`triggerRender`自定义选择框的展示
+如果 Select 默认的触发器样式满足不了你的需求,可以用`triggerRender`自定义选择框的展示  
+如果想保留搜索筛选能力,又不希望自己渲染 Input 相关的结构,可以同时通过 searchPosition='dropdown',将默认的搜索框置于下拉列表中
 
 triggerRender 入参如下
 
@@ -1230,6 +1278,8 @@ import { IconAppCenter, IconChevronDown } from '@douyinfe/semi-icons';
                 optionList={list}
                 onChange={value => setValList(value)}
                 multiple
+                filter
+                searchPosition='dropdown'
                 style={{ width: 240 }}
             ></Select>
             <br />
@@ -1240,6 +1290,8 @@ import { IconAppCenter, IconChevronDown } from '@douyinfe/semi-icons';
                 onChange={value => setVal(value)}
                 triggerRender={triggerRender2}
                 optionList={list}
+                filter
+                searchPosition='dropdown'
                 style={{ width: 240, marginTop: 20, outline: 0 }}
             ></Select>
         </div>
@@ -1394,7 +1446,7 @@ import { Select, Checkbox, Highlight } from '@douyinfe/semi-ui';
 | autoFocus | 初始渲染时是否自动 focus                                                                                                                       | boolean | false |
 | borderless        | 无边框模式  >=2.33.0                                                                                                                       | boolean                         |           |
 | className | 类名                                                                                                                                    | string |  |
-| clearIcon | 可用于自定义清除按钮, showClear为true时有效                                                                                                         | ReactNode | 2.25.0  |
+| clearIcon | 可用于自定义清除按钮, showClear为true时有效                                                                                                         | ReactNode |   | 2.25.0
 | clickToHide | 已展开时,点击选择框是否自动收起下拉列表                                                                                                                  | boolean | false |
 | defaultValue | 初始选中的值                                                                                                                                | string\|number\|array |  |
 | defaultOpen | 是否默认展开下拉列表                                                                                                                            | boolean | false |
@@ -1430,6 +1482,7 @@ import { Select, Checkbox, Highlight } from '@douyinfe/semi-ui';
 | renderOptionItem | 通过 renderOptionItem 完全自定义下拉列表中候选项的渲染                                                                                                  | function(props) 入参详见 Demo |  |
 | restTagsPopoverProps | Popover 的配置属性,可以控制 position、zIndex、trigger 等,具体参考[Popover](/zh-CN/show/popover#API%20%E5%8F%82%E8%80%83)                              | PopoverProps | {} | 2.22.0 |
 | remote | 是否开启远程搜索,当 remote 为 true 时,input 内容改变后不会进行本地筛选匹配                                                                                      | boolean | false |
+| searchPosition | filter开启时,搜索框的位置,默认在 trigger中,可以通过设为 'dropdown' 将搜索框置于下拉列表顶部。搭配 triggerRender 使用可以实现更高自由度的交互   | string | 'trigger' | 2.61.0
 | size | 大小,可选值 `default`/`small`/`large`                                                                                                      | string | 'default' |
 | style | 样式                                                                                                                                    | object |  |
 | stopPropagation | 是否阻止浮层上的点击事件冒泡                                                                                                                        | boolean | true |  |

+ 2 - 0
packages/semi-foundation/select/constants.ts

@@ -14,6 +14,8 @@ const strings = {
     MODE_AUTOCOMPLETE: 'autoComplete',
     // MODE_TAGS: 'tags',
     STATUS: VALIDATE_STATUS,
+    SEARCH_POSITION_TRIGGER: 'trigger',
+    SEARCH_POSITION_DROPDOWN: 'dropdown'
 } as const;
 
 const numbers = { LIST_HEIGHT: 270 };

+ 14 - 4
packages/semi-foundation/select/foundation.ts

@@ -6,6 +6,7 @@ import isNullOrUndefined from '../utils/isNullOrUndefined';
 import { BasicOptionProps } from './optionFoundation';
 import isEnterPress from '../utils/isEnterPress';
 import { handlePrevent } from '../utils/a11y';
+import { strings } from './constants';
 
 export interface SelectAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
     getTriggerWidth(): number;
@@ -18,7 +19,7 @@ export interface SelectAdapter<P = Record<string, any>, S = Record<string, any>>
     rePositionDropdown(): void;
     updateFocusIndex(index: number): void;
     updateSelection(selection: Map<any, any>): void;
-    openMenu(): void;
+    openMenu(cb?: () => void): void;
     notifyDropdownVisibleChange(visible: boolean): void;
     registerClickOutsideHandler(event: any): void;
     toggleInputShow(show: boolean, cb: () => void): void;
@@ -30,6 +31,7 @@ export interface SelectAdapter<P = Record<string, any>, S = Record<string, any>>
     notifyClear(): void;
     updateInputValue(inputValue: string): void;
     focusInput(): void;
+    focusDropdownInput(): void;
     notifySearch(inputValue: string, event?: any): void;
     registerKeyDown(handler: () => void): void;
     unregisterKeyDown(): void;
@@ -367,7 +369,12 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
             // whether it is a filter or not, isFocus is guaranteed to be true when open
             this._adapter.updateFocusState(true);
         }
-        this._adapter.openMenu();
+        this._adapter.openMenu(() => {
+            const { searchPosition, autoFocus } = this.getProps();
+            if (autoFocus && searchPosition === strings.SEARCH_POSITION_DROPDOWN) {
+                this._adapter.focusDropdownInput();
+            }
+        });
         this._setDropdownWidth();
         this._adapter.notifyDropdownVisibleChange(true);
 
@@ -378,6 +385,7 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
             this._notifyBlur(e);
             this._adapter.updateFocusState(false);
         });
+
     }
 
     toggle2SearchInput(isShow: boolean) {
@@ -714,6 +722,8 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
         }
     }
 
+    // When searchPosition is trigger, the keyboard events bind to the outer trigger div
+    // When searchPosition is dropdown, the popup and the outer trigger div are not parent- child relationships, keyboard events bind to the dorpdown input
     _handleKeyDown(event: KeyboardEvent) {
         const key = event.keyCode;
         const { loading, filter, multiple, disabled } = this.getProps();
@@ -1044,8 +1054,8 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
     }
 
     handleClearClick(e: MouseEvent) {
-        const { filter } = this.getProps();
-        if (filter) {
+        const { filter, searchPosition } = this.getProps();
+        if (filter && searchPosition === strings.SEARCH_POSITION_TRIGGER) {
             this.clearInput(e);
         }
         // after click showClear button, the select need to be focused

+ 10 - 1
packages/semi-foundation/select/select.scss

@@ -548,4 +548,13 @@ $overflowList: #{$prefix}-overflow-list;
 }
 
 
-    @import './rtl.scss';
+.#{$module}-dropdown-search-wrapper {
+    padding-top: $spacing-select_dropdown_input_paddingTop;
+    padding-right: $spacing-select_dropdown_input_paddingRight;
+    padding-bottom: $spacing-select_dropdown_input_paddingBottom;
+    padding-top: $spacing-select_dropdown_input_paddingTop;
+    padding-left: $spacing-select_dropdown_input_paddingLeft;
+    border-bottom: 1px solid $color-select_dropdown_input-border;
+}
+
+@import './rtl.scss';

+ 7 - 0
packages/semi-foundation/select/variables.scss

@@ -8,6 +8,8 @@ $color-select-border-hover: $color-select-border-default;  // 选择器输入框
 $color-select-border-active: var(--semi-color-focus-border); // 选择器输入框描边颜色 - 按下态
 $color-select-border-focus: $color-select-border-active;// 选择器输入框描边颜色 - 选中态
 
+$color-select_dropdown_input-border: $color-select-border-default; // 下拉搜索框底部描边颜色
+
 $color-select_warning-bg-default: var(--semi-color-warning-light-default); // 警示选择器输入框背景色 - 默认态
 $color-select_warning-border-default: var(--semi-color-warning-light-default); // 警示选择器输入框描边颜色 - 默认态
 $color-select_warning-bg-hover: var(--semi-color-warning-light-hover); // 警示选择器输入框背景色 - 悬停态
@@ -109,6 +111,11 @@ $spacing-select_option_list-paddingRight: 0px; // 选择器内容区右侧内边
 $spacing-select_option_list-paddingBottom: $spacing-extra-tight; // 选择器内容区底部内边距
 $spacing-select_option_list-paddingLeft: 0px; // 选择器内容区左侧内边距
 
+$spacing-select_dropdown_input_paddingTop: 8px; // 下拉搜索框顶部内边距
+$spacing-select_dropdown_input_paddingBottom: 8px; // 下拉搜索框底部内边距
+$spacing-select_dropdown_input_paddingRight: 12px; // 下拉搜索框右侧内边距
+$spacing-select_dropdown_input_paddingLeft: 12px; // 下拉搜索框左侧内边距
+
 // Radius
 $radius-select: var(--semi-border-radius-small); // 选择器输入框圆角
 $radius-select_option: 0px; // 选择器待选项圆角

+ 31 - 1
packages/semi-ui/select/_story/select.stories.jsx

@@ -3567,4 +3567,34 @@ export const UpdateOtherKeyNotInList = () => {
       <Button id='change' onClick={() => change()}>change</Button>
     </>
   );
-};
+};
+
+export const SearchPosition = () => {
+  
+  return (<>
+        <Select
+          filter
+          searchPosition='dropdown'
+          onChangeWithObject
+          placeholder={'single searchPosition=dropdown'}
+          optionList={optionList}
+          searchPlaceholder='dropdown input place'
+          showClear
+          autoFocus
+          style={{ width: 320 }}
+        />
+        <Select
+          filter
+          multiple
+          placeholder={'multiple searchPosition=dropdown'}
+          searchPosition='dropdown'
+          onChangeWithObject
+          showClear
+          searchPlaceholder='dropdown input place'
+          autoClearSearchValue={false}
+          optionList={optionList}
+          style={{ width: 320 }}
+        />
+    </>
+  )
+}

+ 72 - 11
packages/semi-ui/select/index.tsx

@@ -25,7 +25,7 @@ import Option, { OptionProps } from './option';
 import OptionGroup from './optionGroup';
 import Spin from '../spin';
 import Trigger from '../trigger';
-import { IconChevronDown, IconClear } from '@douyinfe/semi-icons';
+import { IconChevronDown, IconClear, IconSearch } from '@douyinfe/semi-icons';
 import { isSemiIcon, getFocusableElements, getActiveElement, getDefaultPropsFromGlobalConfig } from '../_utils';
 import { getUuidShort } from '@douyinfe/semi-foundation/utils/uuid';
 
@@ -151,6 +151,8 @@ export type SelectProps = {
     defaultActiveFirstOption?: boolean;
     onChangeWithObject?: boolean;
     suffix?: React.ReactNode;
+    searchPosition?: string;
+    searchPlaceholder?: string;
     prefix?: React.ReactNode;
     insetLabel?: React.ReactNode;
     insetLabelId?: string;
@@ -269,6 +271,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
         defaultActiveFirstOption: PropTypes.bool,
         triggerRender: PropTypes.func,
         stopPropagation: PropTypes.bool,
+        searchPosition: PropTypes.string,
         // motion doesn't need to be exposed
         motion: PropTypes.bool,
 
@@ -345,6 +348,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
         defaultActiveFirstOption: true, // In order to meet the needs of A11y, change to true
         showArrow: true,
         showClear: false,
+        searchPosition: strings.SEARCH_POSITION_TRIGGER,
         remote: false,
         autoAdjustOverflow: true,
         autoClearSearchValue: true,
@@ -360,6 +364,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
     })
 
     inputRef: React.RefObject<HTMLInputElement>;
+    dropdownInputRef: React.RefObject<HTMLInputElement>;
     triggerRef: React.RefObject<HTMLDivElement>;
     optionContainerEl: React.RefObject<HTMLDivElement>;
     optionsRef: React.RefObject<any>;
@@ -395,6 +400,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
         this.selectID = '';
         this.virtualizeListRef = React.createRef();
         this.inputRef = React.createRef();
+        this.dropdownInputRef = React.createRef(); // only work when searchPosition = 'dropdown'
         this.triggerRef = React.createRef();
         this.optionsRef = React.createRef();
         this.optionContainerEl = React.createRef();
@@ -444,6 +450,12 @@ class Select extends BaseComponent<SelectProps, SelectState> {
                     this.inputRef.current.focus({ preventScroll });
                 }
             },
+            focusDropdownInput: () => {
+                const { preventScroll } = this.props;
+                if (this.dropdownInputRef && this.dropdownInputRef.current) {
+                    this.dropdownInputRef.current.focus({ preventScroll });
+                }
+            }
         };
         const multipleAdapter = {
             notifyMaxLimit: (option: OptionProps) => this.props.onExceed(option),
@@ -515,8 +527,10 @@ class Select extends BaseComponent<SelectProps, SelectState> {
             updateOptions: (options: OptionProps[]) => {
                 this.setState({ options });
             },
-            openMenu: () => {
-                this.setState({ isOpen: true });
+            openMenu: (cb?: () => void) => {
+                this.setState({ isOpen: true }, () => {
+                    cb?.();
+                });
             },
             closeMenu: () => {
                 this.setState({ isOpen: false });
@@ -658,7 +672,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
 
     handleInputChange = (value: string, event: React.ChangeEvent<HTMLInputElement>) => this.foundation.handleInputChange(value, event);
 
-    renderInput() {
+    renderTriggerInput() {
         const { size, multiple, disabled, inputProps, filter } = this.props;
         const inputPropsCls = get(inputProps, 'className');
         const inputcls = cls(`${prefixcls}-input`, {
@@ -704,6 +718,46 @@ class Select extends BaseComponent<SelectProps, SelectState> {
         );
     }
 
+    renderDropdownInput() {
+        const { size, multiple, disabled, inputProps, filter, searchPosition, searchPlaceholder } = this.props;
+        const { inputValue, focusIndex } = this.state;
+        const wrapperCls = cls(`${prefixcls}-dropdown-search-wrapper`, {
+
+        });
+        const inputPropsCls = get(inputProps, 'className');
+        const inputCls = cls(`${prefixcls}-dropdown-input`, {
+            [`${prefixcls}-dropdown-input-single`]: !multiple,
+            [`${prefixcls}-dropdown-input-multiple`]: multiple,
+        }, inputPropsCls);
+
+        const selectInputProps: Record<string, any> = {
+            value: inputValue,
+            disabled,
+            className: inputCls,
+            onChange: this.handleInputChange,
+            placeholder: searchPlaceholder,
+            showClear: true,
+            ...inputProps,
+            /**
+             * When searchPosition is trigger, the keyboard events are bound to the outer trigger div, so there is no need to listen in input.
+             * When searchPosition is dropdown, the popup and the outer trigger div are not parent- child relationships,
+             * and bubbles cannot occur, so onKeydown needs to be listened in input.
+             *  */ 
+            onKeyDown: (e) => this.foundation._handleKeyDown(e)
+        };
+
+        return (
+            <div className={wrapperCls}>
+                <Input
+                    ref={this.dropdownInputRef}
+                    prefix={<IconSearch></IconSearch>}
+                    aria-activedescendant={focusIndex !== -1 ? `${this.selectID}-option-${focusIndex}` : ''}
+                    {...selectInputProps}
+                />
+            </div>
+        );
+    }
+
     close() {
         this.foundation.close();
     }
@@ -889,7 +943,9 @@ class Select extends BaseComponent<SelectProps, SelectState> {
             loading,
             virtualize,
             multiple,
-            emptyContent
+            emptyContent,
+            searchPosition,
+            filter,
         } = this.props;
 
         // Do a filter first, instead of directly judging in forEach, so that the focusIndex can correspond to
@@ -922,6 +978,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
                 onKeyDown={e => this.foundation.handleContainerKeyDown(e)}
             >
                 {outerTopSlot ? <div className={`${prefixcls}-option-list-outer-top-slot`} onMouseEnter={() => this.foundation.handleSlotMouseEnter()}>{outerTopSlot}</div> : null}
+                {searchPosition === strings.SEARCH_POSITION_DROPDOWN && filter ? this.renderDropdownInput() : null}
                 <div
                     style={{ maxHeight: `${maxHeight}px` }}
                     className={optionListCls}
@@ -939,7 +996,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
     }
 
     renderSingleSelection(selections: Map<OptionProps['label'], any>, filterable: boolean) {
-        let { renderSelectedItem } = this.props;
+        let { renderSelectedItem, searchPosition } = this.props;
         const { placeholder } = this.props;
         const { showInput, inputValue } = this.state;
         let renderText: React.ReactNode = '';
@@ -955,11 +1012,13 @@ class Select extends BaseComponent<SelectProps, SelectState> {
             renderText = (renderSelectedItem as RenderSingleSelectedItemFn)(selectedItem);
         }
 
+        const showInputInTrigger = searchPosition === strings.SEARCH_POSITION_TRIGGER;
+
         const spanCls = cls({
             [`${prefixcls}-selection-text`]: true,
             [`${prefixcls}-selection-placeholder`]: !renderText && renderText !== 0,
-            [`${prefixcls}-selection-text-hide`]: inputValue && showInput, // show Input
-            [`${prefixcls}-selection-text-inactive`]: !inputValue && showInput, // Stack Input & RenderText(opacity 0.4)
+            [`${prefixcls}-selection-text-hide`]: inputValue && showInput && showInputInTrigger, // show Input
+            [`${prefixcls}-selection-text-inactive`]: !inputValue && showInput && showInputInTrigger, // Stack Input & RenderText(opacity 0.4)
         });
 
         const contentWrapperCls = `${prefixcls}-content-wrapper`;
@@ -971,7 +1030,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
                             {renderText || renderText === 0 ? renderText : placeholder}
                         </span>
                     }
-                    {filterable && showInput ? this.renderInput() : null}
+                    {filterable && showInput && showInputInTrigger ? this.renderTriggerInput() : null}
                 </div>
             </>
         );
@@ -1176,7 +1235,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
 
 
     renderMultipleSelection(selections: Map<OptionProps['label'], any>, filterable: boolean) {
-        let { renderSelectedItem } = this.props;
+        let { renderSelectedItem, searchPosition } = this.props;
         const { placeholder, maxTagCount, expandRestTagsOnClick, ellipsisTrigger } = this.props;
         const { inputValue, isOpen } = this.state;
 
@@ -1210,11 +1269,13 @@ class Select extends BaseComponent<SelectProps, SelectState> {
             ? selectedItems.map((item, i) => this.renderTag(item, i))
             : oneLineTags;
 
+        const showTriggerInput = filterable && searchPosition === strings.SEARCH_POSITION_TRIGGER;
+
         return (
             <>
                 <div className={contentWrapperCls}>
                     {selectedItems && selectedItems.length ? tagContent : placeholderText}
-                    {!filterable ? null : this.renderInput()}
+                    {showTriggerInput ? this.renderTriggerInput() : null}
                 </div>
             </>
         );