> Leaf UI 0.6.0 · Package: @ifhover/leaf-ui · Source: b30c3d3a8fa9c5e15d0d0522cebfbd33f60c6b06
> Browser documentation: https://ifhover.github.io/leaf-ui/v/0.6.0/components/tree-select.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/llms-full.txt.

# TreeSelect 树选择器

从层级数据中选择一个或多个值。

## 选择与搜索


当前值: 未选择

basic.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tree-select/basic.tsx"
import { Space, Text, TreeSelect } from '@ifhover/leaf-ui';

import { useState } from 'react';

import { treeOptions } from './options';

export function TreeSelectBasic() {
  const [value, setValue] = useState<string | null>(null);
  return (
    <Space direction="vertical" align="stretch">
      <TreeSelect
        options={treeOptions}
        value={value}
        onChange={setValue}
        defaultExpandAll
        aria-label="所属团队"
        placeholder="选择所属团队"
      />
      <output>
        <Text tone="muted">当前值: {typeof value === 'string' ? value : '未选择'}</Text>
      </output>
    </Space>
  );
}
```

展开代码

## 多选与勾选


多选 · 逐项选择

视觉设计

勾选联动 · 提交子节点

视觉设计

勾选联动 · 合并显示父节点

设计团队

multiple.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tree-select/multiple.tsx"
import { Form, FormField, TreeSelect } from '@ifhover/leaf-ui';

import { treeOptions } from './options';

export function TreeSelectMultiple() {
  return (
    <Form layout="vertical">
      <FormField label="多选 · 逐项选择">
        <TreeSelect options={treeOptions} multiple defaultValue={['visual']} defaultExpandAll />
      </FormField>
      <FormField label="勾选联动 · 提交子节点">
        <TreeSelect
          options={treeOptions}
          treeCheckable
          defaultValue={['visual']}
          defaultExpandAll
        />
      </FormField>
      <FormField label="勾选联动 · 合并显示父节点">
        <TreeSelect
          options={treeOptions}
          treeCheckable
          showCheckedStrategy="parent"
          defaultValue={['design']}
          defaultExpandAll
        />
      </FormField>
    </Form>
  );
}
```

展开代码

## 状态与浮层


禁用

校验反馈

自定义浮层宽度

states.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tree-select/states.tsx"
import { Form, FormField, TreeSelect } from '@ifhover/leaf-ui';

import { treeOptions } from './options';

export function TreeSelectStates() {
  return (
    <Form layout="vertical">
      <FormField label="禁用">
        <TreeSelect options={treeOptions} disabled defaultValue="web" />
      </FormField>
      <FormField label="校验反馈">
        <TreeSelect options={treeOptions} status="error" placeholder="请选择一个团队" />
      </FormField>
      <FormField label="自定义浮层宽度">
        <TreeSelect options={treeOptions} popupWidth={320} popupMaxWidth={360} defaultExpandAll />
      </FormField>
    </Form>
  );
}
```

展开代码

## 扩展用法


extensions.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tree-select/extensions.tsx"
import { TreeSelect } from '@ifhover/leaf-ui';

export function ExtensionDemo() {
  return (
    <TreeSelect
      placeholder="展开团队加载成员"
      options={[{ value: 'team', label: '团队', isLeaf: false }]}
      virtual
      loadData={async (option) => {
        await new Promise((resolve) => setTimeout(resolve, 500));
        return [
          { value: `${option.value}-design`, label: '设计组', isLeaf: true },
          { value: `${option.value}-dev`, label: '开发组', isLeaf: true },
        ];
      }}
    />
  );
}
```

展开代码

## 选择限制与节点展示


最多选择两人，只展示一个标签

capabilities.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tree-select/capabilities.tsx"
import { Flex, Space, Text, TreeSelect } from '@ifhover/leaf-ui';

import { useState } from 'react';

const options = [
  {
    value: 'team',
    label: 'Team',
    children: [
      { value: 'alice', label: 'Alice' },
      { value: 'bob', label: 'Bob' },
      { value: 'carol', label: 'Carol' },
    ],
  },
];

export function Capabilities() {
  const [expanded, setExpanded] = useState<readonly string[]>(['team']);
  return (
    <Space direction="vertical" align="stretch">
      <Flex direction="column" gap="sm" align="center">
        <Text>
          {'最多选择两人，只展示一个标签'}
        </Text>
        <TreeSelect
          treeCheckable
          options={options}
          maxCount={2}
          maxTagCount={1}
          treeExpandedKeys={expanded}
          onExpand={setExpanded}
          nodeRender={(node) => <strong>{node.label}</strong>}
          filterTreeNode={(node, query) =>
            String(node.label).toLowerCase().includes(query.toLowerCase())
          }
          showSearch
        />
      </Flex>
    </Space>
  );
}
```

展开代码

## 单行多选

设置 `tagWrap={false}` 后，已选项始终展示在一行内。长文字自动省略，放不下的选项合并为 `+N`；空间很窄时只显示数量，打开浮层可查看和修改选择。`maxTagCount` 可进一步限制标签数量，`maxTagCount="responsive"` 也会启用单行自动折叠。

再次打开会保留上次展开的分支。不可选分类可点击整行展开；勾选模式可点击整行或按 Enter / 空格勾选，箭头只负责展开或收起。搜索临时展开匹配分支，不改变原有展开状态。


单行多选

视觉设计产品设计前端开发服务端开发+4

single-line.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tree-select/single-line.tsx"
import { Form, FormField, TreeSelect } from '@ifhover/leaf-ui';

import { treeOptions } from './options';

export function SingleLine() {
  return (
    <Form layout="vertical">
      <FormField label="单行多选">
        <TreeSelect
          treeCheckable
          tagWrap={false}
          options={treeOptions}
          defaultValue={['visual', 'product', 'web', 'server']}
          treeDefaultExpandedKeys={['design']}
        />
      </FormField>
    </Form>
  );
}
```

展开代码

## TreeSelect API

| 属性                        | 类型                                                                                                                                                                   | 默认值       | 说明                              |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------------------------------- |
| `popupPlacement`          | `'top' \| 'top-start' \| 'top-end' \| 'bottom' \| 'bottom-start' \| 'bottom-end' \| 'left' \| 'left-start' \| 'left-end' \| 'right' \| 'right-start' \| 'right-end'` | —         | 浮层相对触发控件的位置。                    |
| `popupClassName`          | `string`                                                                                                                                                             | —         | 浮层的自定义类名。                       |
| `popupStyle`              | `CSSProperties`                                                                                                                                                      | —         | 浮层的自定义样式。                       |
| `popupRender`             | `(content: React.ReactNode) => React.ReactNode`                                                                                                                      | —         | 包装或补充面板内容，保留传入的内容以维持交互。         |
| `getPopupContainer`       | `() => Element \| DocumentFragment`                                                                                                                                  | —         | 返回浮层的挂载容器，也可返回 ShadowRoot。      |
| `options`                 | `readonly `[`TreeSelectOption`](#treeselectoption)`[]`                                                                                                               | 必填        | 必需。层级选项                         |
| `checkStrictly`           | `boolean`                                                                                                                                                            | `false`   | 父子节点独立勾选                        |
| `showCheckedStrategy`     | `'child' \| 'parent' \| 'all'`                                                                                                                                       | `'child'` | 勾选后显示与输出子节点、合并父节点或全部节点          |
| `showSearch`              | `boolean`                                                                                                                                                            | `true`    | 通过输入过滤节点                        |
| `onSearch`                | `(query: string) => void`                                                                                                                                            | —         | 搜索文字变化                          |
| `allowClear`              | `boolean`                                                                                                                                                            | `true`    | 允许清除可用选项                        |
| `defaultExpandAll`        | `boolean`                                                                                                                                                            | `false`   | 初始展开全部                          |
| `treeDefaultExpandedKeys` | `readonly string[]`                                                                                                                                                  | `[]`      | 初始展开的 value                     |
| `size`                    | `'sm' \| 'md' \| 'lg'`                                                                                                                                               | `'md'`    | 控件尺寸                            |
| `status`                  | `'error' \| 'warning'`                                                                                                                                               | —         | 校验反馈                            |
| `popupWidth`              | `number \| string`                                                                                                                                                   | `内容宽度`    | 浮层宽度 / 最大宽度；至少与触发器等宽            |
| `popupMaxWidth`           | `number \| string`                                                                                                                                                   | `420`     | 浮层宽度 / 最大宽度；至少与触发器等宽            |
| `notFoundContent`         | `ReactNode`                                                                                                                                                          | 暂无选项      | 无匹配内容                           |
| `onOpenChange`            | `(open: boolean) => void`                                                                                                                                            | —         | 展开状态变化                          |
| `loadData`                | `( option: `[`TreeSelectOption`](#treeselectoption)`, signal: AbortSignal, ) => Promise<readonly `[`TreeSelectOption`](#treeselectoption)`[]>`                       | —         | 展开时加载子项，signal 用于取消             |
| `onLoadError`             | `(error: unknown, option: `[`TreeSelectOption`](#treeselectoption)`) => void`                                                                                        | —         | 加载失败，再次展开可重试                    |
| `virtual`                 | `boolean`                                                                                                                                                            | `false`   | 仅渲染可见项目                         |
| `listHeight`              | `number`                                                                                                                                                             | `256`     | 列表高度                            |
| `itemHeight`              | `number`                                                                                                                                                             | `38`      | 跟随区域控件高度和密度的预估行高，包含行间距；实际行会被测量。 |
| `inputReadOnly`           | `boolean`                                                                                                                                                            | —         | 只禁止手动输入，仍可在面板中选择。               |
| `open`                    | `boolean`                                                                                                                                                            | —         | 控制面板是否展开。                       |
| `defaultOpen`             | `boolean`                                                                                                                                                            | —         | 面板初始展开状态。                       |
| `maxTagCount`             | `number \| 'responsive'`                                                                                                                                             | —         | 最多展示的标签数；responsive 根据可用宽度自动折叠。 |
| `tagWrap`                 | `boolean`                                                                                                                                                            | `true`    | 允许多选标签换行；false 单行显示并自动折叠溢出项。    |
| `maxCount`                | `number`                                                                                                                                                             | —         | 最多可选的数量。                        |
| `treeExpandedKeys`        | `readonly string[]`                                                                                                                                                  | —         | 受控的展开节点。                        |
| `onExpand`                | `(keys: string[]) => void`                                                                                                                                           | —         | 展开节点发生变化时调用。                    |
| `filterTreeNode`          | `(option: `[`TreeSelectOption`](#treeselectoption)`, query: string) => boolean`                                                                                      | —         | 自定义节点的搜索匹配。                     |
| `nodeRender`              | `(option: `[`TreeSelectOption`](#treeselectoption)`) => ReactNode`                                                                                                   | —         | 自定义节点展示内容。                      |
| `cacheKey`                | `string \| number`                                                                                                                                                   | —         | 数据版本改变时清空懒加载缓存，并取消旧请求。          |
| `multiple`                | `false \| true \| boolean`                                                                                                                                           | `false`   | 多选 / 复选框模式，后者自动开启多选             |
| `treeCheckable`           | `false \| boolean \| true`                                                                                                                                           | `false`   | 多选 / 复选框模式，后者自动开启多选             |
| `value`                   | `string \| null \| readonly string[] \| readonly string[]`                                                                                                           | `null`    | 受控 / 初始值；多选使用数组                 |
| `defaultValue`            | `string \| null \| readonly string[] \| readonly string[]`                                                                                                           | `null`    | 受控 / 初始值；多选使用数组                 |
| `onChange`                | `(((value: string \| null) => void) \| ((value: readonly string[]) => void)) \| ((value: readonly string[]) => void)`                                                | —         | 选择变化，清除单选返回 null，多选返回 \[]       |
| `disabled`                | `boolean`                                                                                                                                                            | `false`   | 禁用交互。                           |
| `required`                | `boolean`                                                                                                                                                            | `false`   | 要求整体值非空，复合控件只校验一次。              |
| `name`                    | `string`                                                                                                                                                             | —         | 原生 FormData 中的字段名。              |
| `form`                    | `string`                                                                                                                                                             | —         | 关联的原生表单 ID。                     |

## TreeSelectOption

| 属性                | 类型                                                     | 默认值 | 说明                    |
| ----------------- | ------------------------------------------------------ | --- | --------------------- |
| `value`           | `string`                                               | —   | 必需。唯一值，必填             |
| `label`           | `ReactNode`                                            | —   | 必需。展示内容，必填            |
| `children`        | `readonly `[`TreeSelectOption`](#treeselectoption)`[]` | —   | 子选项，结构相同              |
| `disabled`        | `boolean`                                              | —   | 禁用交互。                 |
| `selectable`      | `boolean`                                              | —   | 设为 false 可让分类节点仅用于浏览  |
| `disableCheckbox` | `boolean`                                              | —   | 禁止勾选并阻断联动             |
| `icon`            | `ReactNode`                                            | —   | 节点图标                  |
| `searchLabel`     | `string`                                               | —   | label 为节点时提供搜索和读屏文字   |
| `isLeaf`          | `boolean`                                              | —   | 明确指定是否为叶子节点，配合异步加载使用。 |

## 类型

可导入以下类型定义属性、组装数据或处理回调。

```ts
import type { TreeSelectProps, TreeSelectOption, TreeSelectValue } from '@ifhover/leaf-ui';
```

## 使用说明

选项的 `value` 应唯一且稳定。示例数据：

```ts lineNumbers file="../../src/examples/tree-select/options.ts"
import type { TreeSelectOption } from '@ifhover/leaf-ui';
export const treeOptions: readonly TreeSelectOption[] = [
  {
    value: 'design',
    label: '设计团队',
    selectable: false,
    children: [
      { value: 'visual', label: '视觉设计' },
      { value: 'product', label: '产品设计' },
      { value: 'archive', label: '归档团队', disabled: true },
    ],
  },
  {
    value: 'engineering',
    label: '研发团队',
    selectable: false,
    children: [
      { value: 'web', label: '前端开发' },
      { value: 'server', label: '服务端开发' },
    ],
  },
];

```

`TreeSelectValue` 是 `string | readonly string[] | null`，可用于组装受控值。复选框默认提交最终子节点；`showCheckedStrategy` 同时决定显示和回调值。禁用的已有选项不会被清除或父子联动修改。

方向键下进入树，Enter 选择，空格勾选，Escape 关闭。多选时，搜索为空按 Backspace 可移除最后一个可用选项。FormData 在同一字段名下提交多个值，使用 `getAll(name)` 读取；非受控字段响应表单 reset。
