> Leaf UI 0.8.1 · Package: @ifhover/leaf-ui · Source: 435bab23cad7d343653d9b63b049c0b0601eeefb
> Browser documentation: https://ifhover.github.io/leaf-ui/components/tree-select.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/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 },
        ];
      }}
    />
  );
}
```

展开代码

## 选择限制与节点展示

浮层默认与控件等宽（`popupWidth="trigger"`）。设置 `popupWidth="auto"` 仅按内容定宽，也可以比控件窄；`popupWidth={300}` 固定为 300px，也支持 CSS 长度。`popupMaxWidth` 默认未设置，下面的示例按内容定宽并显式设置最大宽度。浮层仍会在视口边缘避让。


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

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
          aria-label={'团队成员'}
          popupWidth="auto"
          popupMaxWidth={320}
          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`                                                                                                                                                   | `'trigger'` | 浮层宽度；trigger 与控件等宽，auto 按内容定宽（可比控件窄），数字为固定像素值，也支持 CSS 长度 |
| `popupMaxWidth`           | `number \| string`                                                                                                                                                   | —           | 可选的最大宽度；默认不限制，仍受视口限制                                     |
| `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。
