# 组合框

- 页面: https://jiguang132.com/zh/resources/mantine/docs/combobox
- 资源: Mantine Core (https://jiguang132.com/zh/resources/mantine.md)
- 全部指南: https://jiguang132.com/zh/resources/mantine/docs.md

Mantine Core 的独立组件，请不要替换为 JGuang UI/Base UI 的同名 API。

## 安装

```bash
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1
```

入口引入 `@mantine/core/styles.css`，并在根组件使用 `MantineProvider`；通过 `forceColorScheme` 同步深浅色主题。

## 使用与验证

在左侧选择组件，在预览中操作它的状态；使用“查看代码”检查真实源码。安装后执行类型检查和构建，再验证键盘焦点、手机布局与深浅色主题。

## 来源

https://github.com/mantinedev/mantine/tree/f0e2bc6d28b0f0b8aaefb5b859937bf77f539df7
MIT 许可证；不包括付费内容。下方提供上游英文参考内容，中文使用指南已适配；上游详细参考暂保留英文。

---


## 版本与兼容性

固定的 Mantine Core 9.7.1 要求 React 和 React DOM 满足 `^19.2.0`，并配套 `@mantine/hooks@9.7.1`。此条件来自实际 npm 包的 peerDependencies。React 18 或其他不兼容版本不能强行安装；先向项目负责人说明升级影响并确认方案，不使用 --force/--legacy-peer-deps 掩盖冲突。入口的原生 Provider 开启 `theme.respectReducedMotion`，并用 `forceColorScheme` 控制深浅色。

## 适用场景

通过组合框 store 构建自定义选项选择。

## 本地示例使用的原生参数

以下参数由本地、经过类型检查的 JSX 示例提取，按所属组件区分。不是全部属性清单；完整签名和继承关系见下方固定源码参考。

| 组件参数 | 说明 |
| --- | --- |
| `Combobox.store` | 原生组合框 store，不是 Base UI/Radix 原语。 |
| `Combobox.onOptionSubmit` | 原生选项值提交回调。 |
| `Button.onClick` | 本地点击处理，应按需替换为明确的业务操作。 |
| `Combobox.Option.value` | 受控值，具体结构由原生类型定义。 |

## 交互与状态检查

当前场景：默认。切换支持的禁用、错误或只读场景后检查真实行为；无此原生状态的组件不会被强行添加统一属性。验证键盘焦点和退出方式，修改值后按原生回调签名连接业务状态。

## 业务接入边界

使用原生 useCombobox store，保留 Target/Dropdown/Options/Option 组合；onOptionSubmit 除了关闭列表，还应更新业务选择值。

## 宿主配置

先安装固定版本 @mantine/core 和 @mantine/hooks，在入口引入 @mantine/core/styles.css，并使用 MantineProvider。示例的 theme 和 variant 是 JGuang 编写的宿主参数，不是所有原生组件都接受的统一 API；通过 forceColorScheme 同步应用主题。源码面板中的原生实现仅供阅读，使用 npm 导出，不要单独复制内部实现。此批只覆盖 Core，不包括日期、图表和表单扩展包。上游详细说明保留英文，不宣称全文中文化。


## 可运行用法

以下代码使用资源原生 API；不是把其他设计系统的同名组件替换进来。

```tsx
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';

const fruit = ["Apple", "Banana", "Orange"];
function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const [value, setValue] = useState(35);
const [selection, setSelection] = useState<string | null>(null);
const combo = M.useCombobox();
return <M.Combobox store={combo} onOptionSubmit={(next) => { setSelection(next); combo.closeDropdown(); }}><M.Combobox.Target><M.Button onClick={() => combo.toggleDropdown()}>{selection ?? "Choose a fruit / 选择水果"}</M.Button></M.Combobox.Target><M.Combobox.Dropdown><M.Combobox.Options>{fruit.map((fruit) => <M.Combobox.Option key={fruit} value={fruit}>{fruit}</M.Combobox.Option>)}</M.Combobox.Options></M.Combobox.Dropdown></M.Combobox>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

```


## 可用状态与示例

默认

示例遵循 Mantine 原生 API。支持多状态的输入组件可将示例中的 variant 改为 Disabled、Invalid 或 Read only；这些只是示例标签，不是新增的组件属性。改造时保留组件要求的数据、受控值、store 和复合子组件结构。


## Examples

This page contains only a small set of examples, as the full code of the demos is long.
You can find all 50+ examples on a [separate page](/combobox?e=BasicSelect).


## Usage

`Combobox` provides a set of components and hooks to create custom select, multiselect or autocomplete components.
The component is very flexible – you have full control of the rendering and logic.



## useCombobox hook

`useCombobox` hook provides a combobox store. The store contains the current state of the component
and handlers to update it. The created store must be passed to the `store` prop of `Combobox`:

```tsx
import { Combobox, useCombobox } from '@mantine/core';

function Demo() {
  const combobox = useCombobox();
  return (
    <Combobox store={combobox}>{/* Your implementation */}</Combobox>
  );
}
```

## useCombobox options

The `useCombobox` hook accepts an options object with the following properties:

```tsx
interface UseComboboxOptions {
  /** Default value for `dropdownOpened`, `false` by default */
  defaultOpened?: boolean;

  /** Controlled `dropdownOpened` state */
  opened?: boolean;

  /** Called when `dropdownOpened` state changes */
  onOpenedChange?(opened: boolean): void;

  /** Called when dropdown closes with event source: keyboard, mouse or unknown */
  onDropdownClose?(eventSource: ComboboxDropdownEventSource): void;

  /** Called when dropdown opens with event source: keyboard, mouse or unknown */
  onDropdownOpen?(eventSource: ComboboxDropdownEventSource): void;

  /** Determines whether arrow key presses should loop though items (first to last and last to first), `true` by default */
  loop?: boolean;

  /** `behavior` passed down to `element.scrollIntoView`, `'instant'` by default */
  scrollBehavior?: ScrollBehavior;
}
```

You can import the `UseComboboxOptions` type from the `@mantine/core` package:

```tsx
import type { UseComboboxOptions } from '@mantine/core';
```

## Combobox store

The Combobox store is an object with the following properties:

```tsx
interface ComboboxStore {
  /** Current dropdown opened state */
  dropdownOpened: boolean;

  /** Opens dropdown */
  openDropdown(eventSource?: 'keyboard' | 'mouse' | 'unknown'): void;

  /** Closes dropdown */
  closeDropdown(eventSource?: 'keyboard' | 'mouse' | 'unknown'): void;

  /** Toggles dropdown opened state */
  toggleDropdown(
    eventSource?: 'keyboard' | 'mouse' | 'unknown'
  ): void;

  /** Selected option index */
  selectedOptionIndex: number;

  /** Selects `Combobox.Option` by index */
  selectOption(index: number): void;

  /** Selects first `Combobox.Option` with `active` prop.
   *  If there are no such options, the function does nothing.
   */
  selectActiveOption(): string | null;

  /** Selects first `Combobox.Option` that is not disabled.
   *  If there are no such options, the function does nothing.
   * */
  selectFirstOption(): string | null;

  /** Selects next `Combobox.Option` that is not disabled.
   *  If the current option is the last one, the function selects first option, if `loop` is true.
   */
  selectNextOption(): string | null;

  /** Selects previous `Combobox.Option` that is not disabled.
   *  If the current option is the first one, the function selects last option, if `loop` is true.
   * */
  selectPreviousOption(): string | null;

  /** Resets selected option index to -1, removes `data-combobox-selected` from selected option */
  resetSelectedOption(): void;

  /** Triggers `onClick` event of selected option.
   *  If there is no selected option, the function does nothing.
   */
  clickSelectedOption(): void;

  /** Updates selected option index to currently selected or active option.
   *  The function is required to be used with searchable components to update selected option index
   *  when options list changes based on search query.
   */
  updateSelectedOptionIndex(target?: 'active' | 'selected'): void;

  /** List id, used for `aria-*` attributes */
  listId: string | null;

  /** Sets list id */
  setListId(id: string): void;

  /** Ref of `Combobox.Search` input */
  searchRef: React.RefObject<HTMLInputElement | null>;

  /** Moves focus to `Combobox.Search` input */
  focusSearchInput(): void;

  /** Ref of the target element */
  targetRef: React.RefObject<HTMLElement | null>;

  /** Moves focus to the target element */
  focusTarget(): void;
}
```

You can import `ComboboxStore` type from `@mantine/core` package:

```tsx
import type { ComboboxStore } from '@mantine/core';
```

## useCombobox handlers

Combobox store handlers can be used to control `Combobox` state.
For example, to open the dropdown, call `openDropdown` handler:

```tsx
import { Button, Combobox, useCombobox } from '@mantine/core';

function Demo() {
  const combobox = useCombobox();

  return (
    <Combobox>
      <Combobox.Target>
        <Button onClick={() => combobox.openDropdown()}>
          Open dropdown
        </Button>
      </Combobox.Target>

      {/* Your implementation */}
    </Combobox>
  );
}
```

You can use store handlers in `useCombobox` options. For example, you can
call `selectFirstOption` when the dropdown is opened and `resetSelectedOption`
when it is closed:

```tsx
import { Combobox, useCombobox } from '@mantine/core';

function Demo() {
  const combobox = useCombobox({
    onDropdownOpen: () => combobox.selectFirstOption(),
    onDropdownClose: () => combobox.resetSelectedOption(),
  });

  return (
    <Combobox store={combobox}>{/* Your implementation */}</Combobox>
  );
}
```

## Combobox.Target

`Combobox.Target` should be used as a wrapper for the target element or component.
`Combobox.Target` marks its child as a target for dropdown and sets `aria-*` attributes
and adds keyboard event listeners to it.

`Combobox.Target` requires a single child element or component. The child component
must accept `ref` and `...others` props. You can use any Mantine component as a target without
any additional configuration, for example, [Button](/core/button/), [TextInput](/core/text-input/)
or [InputBase](/core/input/#inputbase-component).

Example of using `Combobox.Target` with [TextInput](/core/text-input/) component:



Example of using `Combobox.Target` with [Button](/core/button) component:



## Split events and dropdown targets

In some cases, you might need to use different elements as an events target and as a dropdown.
Use `Combobox.EventsTarget` to add `aria-*` attributes and keyboard event handlers, and
`Combobox.DropdownTarget` to position the dropdown relative to the target.

You can have as many `Combobox.EventsTarget` as you need, but only one `Combobox.DropdownTarget`
per `Combobox`.

Example of using `Combobox.EventsTarget` and `Combobox.DropdownTarget` with [PillsInput](/core/pills-input) component
to create a searchable multiselect component:



## Update selected option index

`updateSelectedOptionIndex` handler is required to be called when options list changes.
Usually, the options list changes when options are filtered based on the search query. In this case,
you need to call `updateSelectedOptionIndex` in `onChange` handler of the search input.

Example of using `updateSelectedOptionIndex` handler in searchable select component:



## Search input

If you prefer search input inside the dropdown, use `Combobox.Search` component.
To focus the search input, call `combobox.focusSearchInput`, usually it is done
when the dropdown is opened. To prevent focus loss after the dropdown is closed,
call `combobox.focusTarget`:



## Select first option

Use `combobox.selectFirstOption` function to select the first option. It is useful
if you want to select the first option when user searching for options in the list.
If there are no options available, it will do nothing.



## Active option

Set `active` prop on `Combobox.Option` component to mark it as active.
By default, an active option does not have any styles, you can use `data-combobox-active`
[data attribute](/styles/data-attributes) to style it.

`combobox.selectActiveOption` function selects active option. Usually, it is called
when the dropdown is opened:



## Options groups

Render `Combobox.Option` components inside `Combobox.Group` to create options group.
`Combobox.Group` label will be automatically hidden if the group does not have any
children.



## Scrollable list

Set `max-height` style on either `Combobox.Dropdown` or `Combobox.Options` to make the
options list scrollable. You can use `mah` [style prop](/styles/style-props) to set
`max-height`.



## Scrollable list with ScrollArea

You can also use [ScrollArea or ScrollArea.Autosize](/core/scroll-area) components
instead of native scrollbars:



## Fit dropdown to viewport height

Set `floatingHeight="viewport"` to make the dropdown grow to fill the available vertical
space in the viewport. The dropdown size is recalculated automatically when the trigger
position changes. When the prop is set, the `flip` middleware is disabled – the dropdown
always opens in the configured direction and is constrained to the viewport edges instead
of flipping to the other side.

The dropdown exposes a `--combobox-floating-options-max-height` CSS variable equal to the
available height minus the dropdown padding. Pass it as `mah` to your `ScrollArea.Autosize`
(or use it on any element you want to scroll within the bounded dropdown):



## Hide dropdown

Set `hidden` prop on `Combobox.Dropdown` to hide the dropdown. For example,
it can be useful when you want to show the dropdown only when there is at least
one option available:



## Control dropdown opened state

To control the dropdown opened state, pass `opened` to `useCombobox` hook:



## Popover props

`Combobox` supports most of [Popover](/core/popover) props. For example,
you can control dropdown position with `position` prop and disable Floating UI
middlewares with `middlewares` prop:



## Without dropdown

You can use `Combobox` without dropdown. To do so, use `Combobox.EventsTarget` instead
of `Combobox.Target`:






## Virtualization

`useVirtualizedCombobox` hook can be used to create comboboxes with virtualized options list.
Note that due to the nature of virtualization, the hook requires some additional configuration
compared to the `useCombobox` hook. In `useVirtualizedCombobox` hook all operations related to
option indexing do not rely on the actual DOM structure, instead, you need to preserve values in
React state and pass them to the hook.

`useVirtualizedCombobox` does not depend on any specific virtualization library.
The recommended option is [@tanstack/react-virtual](https://tanstack.com/virtual/latest):



Example of implementation with [react-virtuoso](https://virtuoso.dev/):



You can find more virtualization examples on the [Combobox examples page](/combobox?e=VirtualizedTanstack).

Hook options:

```tsx
export interface UseVirtualizedComboboxOptions {
  /** Default value for `dropdownOpened`, `false` by default */
  defaultOpened?: boolean;

  /** Controlled `dropdownOpened` state */
  opened?: boolean;

  /** Called when `dropdownOpened` state changes */
  onOpenedChange?: (opened: boolean) => void;

  /** Called when dropdown closes */
  onDropdownClose?: (eventSource: ComboboxDropdownEventSource) => void;

  /** Called when dropdown opens */
  onDropdownOpen?: (eventSource: ComboboxDropdownEventSource) => void;

  /** Determines whether arrow key presses should loop though items (first to last and last to first), `true` by default */
  loop?: boolean;

  /** Function to determine whether the option is disabled */
  isOptionDisabled?: (optionIndex: number) => boolean;

  /** Total number of options in the virtualized list. Required for proper keyboard navigation and index calculations. */
  totalOptionsCount: number;

  /** Function that returns the id of the option at the given index. Required for setting aria attributes and element references. */
  getOptionId: (index: number) => string | null;

  /** Current selected option index. Must be controlled by parent component. */
  selectedOptionIndex: number;

  /** Callback to update the selected option index. Called when user navigates or selects options. */
  setSelectedOptionIndex: (index: number) => void;

  /** Currently active/highlighted option index. Used to determine which option to select when selectActiveOption is called. */
  activeOptionIndex?: number;

  /** Called when the selected option is submitted (e.g., via Enter key or clicking). Receives the selected option index. */
  onSelectedOptionSubmit: (index: number) => void;
}
```


## 源码参数参考

以下实现签名和类型从本地固定版本源码生成。保留可选属性、原生继承类型、联合分支和 never 限制；不会将其他设计系统的 API 混入。forwardRef 实现中的 ref 属于 React 引用，不是新增业务属性。此区域是原始类型参考，不是上游说明的全文翻译。


```ts
Combobox(_props: ComboboxProps)
```



```ts
export type ComboboxStylesNames =
  | 'options'
  | 'dropdown'
  | 'option'
  | 'search'
  | 'empty'
  | 'footer'
  | 'header'
  | 'group'
  | 'groupLabel';

export type ComboboxCSSVariables = {
  options: '--combobox-option-fz' | '--combobox-option-padding';
  dropdown: '--combobox-padding' | '--combobox-option-fz' | '--combobox-option-padding';
};

export interface ComboboxProps extends __PopoverProps, StylesApiProps<ComboboxFactory> {
  __staticSelector?: string;

  /** Combobox content */
  children?: React.ReactNode;

  /** Combobox store, can be used to control combobox state */
  store?: ComboboxStore;

  /** Called when item is selected with the `Enter` key or by clicking it */
  onOptionSubmit?: (value: string, optionProps: ComboboxOptionProps) => void;

  /** Controls items `font-size` and `padding` @default 'sm' */
  size?: MantineSize | (string & {});

  /** Controls `padding` of the dropdown @default 4 */
  dropdownPadding?: React.CSSProperties['padding'];

  /** Determines whether selection should be reset when option is hovered @default false */
  resetSelectionOnOptionHover?: boolean;

  /** Determines whether the `Combobox` value can be changed */
  readOnly?: boolean;

  /** If set to `'viewport'`, the dropdown grows to fill the available vertical space in the viewport. Disables the `flip` middleware. */
  floatingHeight?: 'viewport';
}

export type ComboboxFactory = Factory<{
  props: ComboboxProps;
  ref: HTMLDivElement;
  stylesNames: ComboboxStylesNames;
  vars: ComboboxCSSVariables;
  staticComponents: {
    Target: typeof ComboboxTarget;
    Dropdown: typeof ComboboxDropdown;
    Options: typeof ComboboxOptions;
    Option: typeof ComboboxOption;
    Search: typeof ComboboxSearch;
    Empty: typeof ComboboxEmpty;
    Chevron: typeof ComboboxChevron;
    Footer: typeof ComboboxFooter;
    Header: typeof ComboboxHeader;
    EventsTarget: typeof ComboboxEventsTarget;
    DropdownTarget: typeof ComboboxDropdownTarget;
    Group: typeof ComboboxGroup;
    ClearButton: typeof ComboboxClearButton;
    HiddenInput: typeof ComboboxHiddenInput;
  };
}>;
```


### 原生与外部类型

以下外部类型仍由 React 或资源自身依赖定义，没有手工展开为虚构属性。实际可用类型以安装版本的 TypeScript 检查为准。


```ts
__PopoverProps
StylesApiProps<ComboboxFactory>
Factory<{
  props: ComboboxProps;
  ref: HTMLDivElement;
  stylesNames: ComboboxStylesNames;
  vars: ComboboxCSSVariables;
  staticComponents: {
    Target: typeof ComboboxTarget;
    Dropdown: typeof ComboboxDropdown;
    Options: typeof ComboboxOptions;
    Option: typeof ComboboxOption;
    Search: typeof ComboboxSearch;
    Empty: typeof ComboboxEmpty;
    Chevron: typeof ComboboxChevron;
    Footer: typeof ComboboxFooter;
    Header: typeof ComboboxHeader;
    EventsTarget: typeof ComboboxEventsTarget;
    DropdownTarget: typeof ComboboxDropdownTarget;
    Group: typeof ComboboxGroup;
    ClearButton: typeof ComboboxClearButton;
    HiddenInput: typeof ComboboxHiddenInput;
  };
}>
HTMLDivElement
React.ReactNode
ComboboxStore
ComboboxOptionProps
MantineSize
React.CSSProperties
```

---

JGuang 全部资源索引: https://jiguang132.com/llms.txt
