You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中MUI Autocomplete组件实现永久可见自定义分组的问题

MUI Autocomplete 本身没有提供这种固定显示分组、过滤不隐藏分组头的开箱即用能力,但可以通过自定义过滤逻辑和渲染逻辑实现,无需修改组件底层。

实现思路
  • 放弃默认的groupBy属性,改用特殊的插入式分组逻辑,从根源上保证分组头不会被过滤逻辑移除
  • 改造filterOptions逻辑,过滤完成后将两个分组的头作为特殊选项插入到结果列表的对应位置,无论分组下是否有匹配项,都会保留分组头
  • 重写renderOption方法区分渲染分组头和普通选项,给分组头设置disabled属性,避免被当成可选项处理,也不会被默认的选项匹配逻辑干扰
  • 在选项相等判断、禁用判断等逻辑中过滤掉分组头特殊选项,保证正常的选择逻辑不受影响
核心代码示例
import Autocomplete from '@mui/material/Autocomplete';
import ListSubheader from '@mui/material/ListSubheader';
import TextField from '@mui/material/TextField';

// 提前给所有选项添加分组标识,按需对应你的两个分组
const options = [
  { label: '常用选项1', group: 'frequent' },
  { label: '常用选项2', group: 'frequent' },
  { label: '全部选项1', group: 'all' },
  { label: '全部选项2', group: 'all' },
];

const CustomGroupAutocomplete = () => {
  const customFilter = (options, { inputValue }) => {
    const searchKey = inputValue.trim().toLowerCase();
    // 分别过滤两个分组的匹配选项
    const frequentOptions = options.filter(
      opt => opt.group === 'frequent' && opt.label.toLowerCase().includes(searchKey)
    );
    const allOptions = options.filter(
      opt => opt.group === 'all' && opt.label.toLowerCase().includes(searchKey)
    );

    // 把分组头作为特殊选项插入返回结果,保证分组始终可见
    return [
      { type: 'header', label: '常用选项' },
      ...frequentOptions,
      // 可选:分组无匹配时显示占位提示
      ...(frequentOptions.length === 0 ? [{ type: 'empty', label: '无匹配常用选项' }] : []),
      { type: 'header', label: '全部选项' },
      ...allOptions,
      ...(allOptions.length === 0 ? [{ type: 'empty', label: '无匹配选项' }] : [])
    ];
  };

  return (
    <Autocomplete
      options={options}
      filterOptions={customFilter}
      getOptionLabel={option => option.label || ''}
      // 排除特殊选项,避免分组头/占位符被当成可选项
      isOptionEqualToValue={(option, value) => !option.type && option.label === value.label}
      getOptionDisabled={option => !!option.type}
      renderOption={(props, option) => {
        // 渲染分组头
        if (option.type === 'header') {
          return <ListSubheader component="li" {...props} sx={{ fontSize: '14px', fontWeight: 700 }}>{option.label}</ListSubheader>;
        }
        // 渲染空占位
        if (option.type === 'empty') {
          return <li {...props} sx={{ color: 'text.secondary', fontSize: '13px' }}>{option.label}</li>;
        }
        // 渲染普通可选选项
        return <li {...props}>{option.label}</li>;
      }}
      renderInput={(params) => <TextField {...params} label="选择选项" variant="outlined" />}
    />
  );
};
注意事项
  • 特殊选项的type字段可以自定义,只要和普通选项的字段区分开即可
  • 如果需要调整分组的样式,直接修改renderOption中分组头的样式属性即可,支持完全自定义的分组视觉效果
  • 该方案兼容Autocomplete的多选、高亮搜索关键字等原生能力,不需要额外适配

内容的提问来源于stack exchange,提问作者Norayr Ghukasyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 14:15:07