When to Use
When the options to select is in tree structure, you could use TreeSelect, e.g. department hierarchy, subject system, category directory and etc.
Demos
How to import
import { TreeSelect } from '@fibrous/semi-ui-solid';
Basic Usage
By default, TreeSelect is in single select mode and each item is selectable.
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
return <TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} placeholder="请选择" />;
}Multi-choice
You could use multiple to set mode to multi-choice. When all child items are selected, the parent item will be selected.
Use leafOnly if you prefer to render leaf nodes only and the corresponding params for onChange will also be leaf nodes values.
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
{
label: 'Chengdu',
value: 'Chengdu',
key: '0-0-2',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
export default function TreeSelectDemo() {
return (
<div>
<TreeSelect style={{ width: '300px' }} multiple dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} placeholder="请选择" />
<br />
<br />
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple leafOnly placeholder="只渲染叶子节点" />
<br />
<br />
</div>
);
}Limit Tags Number
In the multi-selection scenario, maxTagCount can be used to limit the number of tags displayed, and the excess part will be displayed in the form of +N.
Use showRestTagsPopover (>= v2.22.0) to set whether hover +N displays Popover after exceeding maxTagCount, the default is false. Also, popovers can be configured in the restTagsPopoverProps property.
maxTagCount=2:
maxTagCount=2, showRestTagsPopover:
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
{
label: 'Chengdu',
value: 'Chengdu',
key: '0-0-2',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
const textStyle = { margin: '20px 0 10px' };
export default function TreeSelectDemo() {
return (
<div>
<h4 style={textStyle}>maxTagCount=2:</h4>
<TreeSelect multiple maxTagCount={2} style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} placeholder="当选中标签超过两个将折叠" defaultValue={['Beijing', 'Chengdu', 'Canada']} />
<h4 style={textStyle}>maxTagCount=2, showRestTagsPopover:</h4>
<TreeSelect showRestTagsPopover restTagsPopoverProps={{ position: 'top' }} multiple maxTagCount={2} style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} placeholder="hover +N 查看" defaultValue={['Beijing', 'Chengdu', 'Canada']} />
</div>
);
}Searchable
Use filterTreeNode to support search input. By default it searches the label property of the data. You can use treeNodeFilterProp to set another property to search or pass in a function to filterTreeNode to customize search behavior.
You could also use showFilteredOnly if you prefer to display filtered results only.
If you want to get specific information about the search results, you can use the onSearch callback function. See the API list for the specific parameters of the function.
Code
import { createSignal } from 'solid-js';
import { Switch, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
function onSearch(inputValue: string, filteredExpandedKeys: string[], filteredNodes: TreeNodeData[]) {
console.log('onSearch', inputValue, filteredExpandedKeys, filteredNodes);
}
export default function TreeSelectDemo() {
const [showFilteredOnly, setShowFilteredOnly] = createSignal(false);
return (
<>
<span id="treeselect-searchable-filtered-only">showFilteredOnly</span>
<Switch aria-labelledby="treeselect-searchable-filtered-only" checked={showFilteredOnly()} onChange={(checked) => setShowFilteredOnly(checked)} size="small" />
<br />
<br />
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} filterTreeNode showFilteredOnly={showFilteredOnly()} placeholder="单选可搜索的" onSearch={onSearch} />
<br />
<br />
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple filterTreeNode maxTagCount={2} showFilteredOnly={showFilteredOnly()} placeholder="多选可搜索的" searchPlaceholder="请输入关键字开始搜索" onSearch={onSearch} />
<br />
<br />
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple filterTreeNode maxTagCount={2} showFilteredOnly={showFilteredOnly()} placeholder="搜索框autofocus" searchPlaceholder="autofocus" searchAutoFocus onSearch={onSearch} />
</>
);
}Remote Search
By setting the remote property, you can enable remote search. When enabled, local filtering is skipped on input, only the onSearch callback is triggered, allowing users to handle remote data fetching and update treeData.
Code
import { createSignal } from 'solid-js';
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-solid';
export default function TreeSelectDemo() {
const [value, setValue] = createSignal<string | number>();
const [treeData, setTreeData] = createSignal<TreeNodeData[]>([]);
function handleSearch(inputValue: string) {
if (!inputValue) {
setTreeData([]);
return;
}
setTimeout(() => {
const mockData = [
{ label: `${inputValue} - 结果1`, value: `${inputValue}-1`, key: `${inputValue}-1` },
{ label: `${inputValue} - 结果2`, value: `${inputValue}-2`, key: `${inputValue}-2` },
{ label: `${inputValue} - 结果3`, value: `${inputValue}-3`, key: `${inputValue}-3` },
];
setTreeData(mockData);
}, 500);
}
return <TreeSelect style={{ width: '300px' }} placeholder="请输入关键字进行远程搜索" treeData={treeData()} filterTreeNode remote value={value()} onChange={(next) => setValue(next)} onSearch={handleSearch} />;
}Search Box Position
You can use searchPosition to set the position of the search box, optional: dropdown (default), trigger.
When the input box is at trigger:
- The placeholder of the search box is controlled by
placeholder; - When
showClear=true, click the clear button of the input box, the inputValue and value will be cleared at the same time.
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
export default function TreeSelectDemo() {
return (
<>
<TreeSelect searchPosition="trigger" style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} filterTreeNode placeholder="单选" />
<br />
<br />
<TreeSelect searchPosition="trigger" style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple filterTreeNode maxTagCount={2} placeholder="多选" />
</>
);
}Wrap tags in trigger (triggerTagWrap)
In multiple + searchable + searchPosition="trigger" mode, if there are many selected items or the input is long, the trigger may prefer to keep a single-line layout by default.
Turn on triggerTagWrap to allow selected tags to wrap into multiple lines within the trigger.
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
{
label: 'Shenzhen',
value: 'Shenzhen',
key: '0-0-2',
},
{
label: 'Guangzhou',
value: 'Guangzhou',
key: '0-0-3',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
export default function TreeSelectDemo() {
return <TreeSelect searchPosition="trigger" triggerTagWrap style={{ width: '260px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple filterTreeNode placeholder="请选择多个选项或输入长文本" defaultValue={['Beijing', 'Shanghai', 'Shenzhen', 'Guangzhou']} />;
}Size
You can set the size by size, one of: 'small'、'default'、'large'
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
return (
<div>
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple size="small" placeholder="small" />
<br />
<br />
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple size="default" placeholder="default" />
<br />
<br />
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple size="large" placeholder="large" />
</div>
);
}Default Expand All
Both defaultExpandAll and expandAll can set the default expanded/collapsed state of TreeSelect. The difference between the two is that defaultExpandAll only takes effect during initialization, while expandAll will take effect not only during initialization, but also when the data (treeData) is dynamically updated.
In the demo below, after TreeData is updated, defaultExpandAll becomes invalid, and expandAll still takes effect.
Code
import { createSignal, onCleanup, onMount } from 'solid-js';
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-solid';
const treeData: TreeNodeData[] = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
const [data, setData] = createSignal<TreeNodeData[]>([]);
onMount(() => {
const timer = setTimeout(() => setData(treeData), 500);
onCleanup(() => clearTimeout(timer));
});
return (
<>
<TreeSelect style={{ width: '300px', 'margin-bottom': '20px' }} expandAll treeData={data()} placeholder="expandAll" />
<TreeSelect style={{ width: '300px' }} defaultExpandAll treeData={data()} placeholder="defaultExpandAll" />
</>
);
}Disabled
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
return (
<div>
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} disabled placeholder="禁用下拉菜单" />
<br />
<br />
<TreeSelect style={{ width: '300px' }} defaultValue="Shanghai" dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} disabled />
<br />
<br />
<TreeSelect style={{ width: '300px' }} defaultValue={['Shanghai', 'North America']} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} multiple disabled />
</div>
);
}Disable Strictly
You can use disableStrictly to enable strict disabling. After enabling strict disabling, when the node is disabled, the selected state cannot be changed through the relationship between the child or the parent.
Take the following demo as an example, the node "China" is strictly disabled. Therefore, when we change the selected state of its parent node "Asia", it will not affect the selected state of the node "China".
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
disabled: true,
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
{
label: '日本',
value: 'Japan',
key: '0-1',
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
return (
<div>
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} disableStrictly multiple defaultValue={['Shanghai']} />
</div>
);
}Controlled Component
You can use value along with onChange property if you want to use TreeSelect as a controlled component.
Code
import { createSignal } from 'solid-js';
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
const [value, setValue] = createSignal<string | undefined>('Shanghai');
return <TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} value={value()} placeholder="请选择" onChange={(next) => setValue(next)} />;
}Checked RelationShip
Version: >= 2.5.0
In multiple, checkRelation can be used to set the type of node selection relationship, optional: 'related' (default), 'unRelated'. When the selection relationship is 'unRelated', it means that selections between nodes do not affect each other.
Code
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
return <TreeSelect multiple defaultValue={['Asia']} checkRelation="unRelated" style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} />;
}Controlled Expansion with Search
When expandedKeys is passed in, it is a controlled expansion component, which can be used with onExpand. When the expansion is controlled, if the filterTreeNode is turned on and the search is performed, the node will no longer be automatically expanded. At this time, the expansion of the node is completely controlled by the expandedKeys. You can use the parameter filteredExpandedKeys of onSearch to realize the search expansion effect when the expansion is controlled.
Code
import { createSignal } from 'solid-js';
import { TreeSelect } from '@fibrous/semi-ui-solid';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
{
label: '日本',
value: 'Japan',
key: '0-1',
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
export default function TreeSelectDemo() {
const [expandedKeys, setExpandedKeys] = createSignal<string[]>([]);
return (
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData} filterTreeNode expandedKeys={expandedKeys()} onExpand={(keys) => setExpandedKeys(keys)} onSearch={(_, filteredExpandedKeys) => setExpandedKeys([...filteredExpandedKeys, ...expandedKeys()])} />
);
}Virtualized TreeSelect
If you need to render large sets of tree structured data, you could use virtualized tree. In virtualized mode, animation / motion is disabled for better performance.
The property virtualize is an object consisting of the following values:
- height: Height of the dropDown, If passed in as a string, computed height should not be zero for render purpose, in other words, parent node should have offsetHeight. Pass in a number recommended.
- width: Width of the dropDown.
- itemSize: Height for each line of treeNode, required
If tree is searchable, you could also turn on showFilteredOnly to reduce time of rendering for results.
Code
import { createSignal, Show } from 'solid-js';
import { Button, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-solid';
// x: nodes per level. y: nodes with children per level. z: depth (0 is one level)
function generateData(x = 5, y = 4, z = 3) {
const data: TreeNodeData[] = [];
function fill(level: number, preKey: string, nodes: TreeNodeData[]) {
const parents: string[] = [];
for (let i = 0; i < x; i++) {
const key = `${preKey}-${i}`;
nodes.push({ label: `${key}-标签`, key: `${key}-key`, value: `${key}-value` });
if (i < y) {
parents.push(key);
}
}
if (level < 0) {
return;
}
parents.forEach((key, index) => {
const children: TreeNodeData[] = [];
nodes[index].children = children;
fill(level - 1, key, children);
});
}
fill(z, '0', data);
let total = 0;
for (let n = z + 1; n >= 0; n--) {
total += x * y ** n;
}
return { gData: data, total };
}
export default function TreeSelectDemo() {
const [gData, setGData] = createSignal<TreeNodeData[]>([]);
const [total, setTotal] = createSignal(0);
function onGen() {
const generated = generateData();
setGData(generated.gData);
setTotal(generated.total);
}
return (
<div style={{ padding: '0 20px' }}>
<Button onClick={onGen}>生成数据: </Button>
<span>共 {total()} 个节点</span>
<br />
<br />
<Show when={gData().length > 0}>
<TreeSelect
style={{ width: '300px' }}
treeData={gData()}
filterTreeNode
showFilteredOnly
placeholder="Please select"
dropdownStyle={{ overflow: 'hidden' }}
virtualize={{
itemSize: 28,
// Dropdown height 300 minus the search box and 8 * 2 padding; a set height fills the rest
height: 236,
}}
/>
</Show>
</div>
);
}Dynamic Update of Data
Code
import { createSignal } from 'solid-js';
import { Button, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-solid';
export default function TreeSelectDemo() {
const [treeData, setTreeData] = createSignal<TreeNodeData[]>([]);
function add() {
const itemLength = Math.floor(Math.random() * 5) + 1;
const nextTreeData = Array.from({ length: itemLength }, (_v, i) => {
const length = Math.floor(Math.random() * 3);
const children = Array.from({ length }, (_cv, ci) => {
const child = {
key: `${i}-${ci}`,
label: `Leaf-${i}-${ci}`,
value: `${i}-${ci}`,
};
return child;
});
const item = {
key: `${i}`,
label: `Item-${i}`,
value: `${i}`,
children,
};
return item;
});
setTreeData(nextTreeData);
}
return (
<>
<TreeSelect style={{ width: '300px' }} dropdownStyle={{ 'max-height': '400px', overflow: 'auto' }} treeData={treeData()} placeholder="请选择" />
<br />
<br />
<Button onClick={add}>动态改变数据</Button>
</>
);
}Load Data Asynchronously
You could use loadData to load treeData asynchronously on node expansion. Notice isLeaf is required to mark node as leaf in treeData.
Code
import { createSignal } from 'solid-js';
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-solid';
const initialData: TreeNodeData[] = [
{
label: 'Expand to load',
value: '0',
key: '0',
},
{
label: 'Expand to load',
value: '1',
key: '1',
},
{
label: 'Leaf Node',
value: '2',
key: '2',
isLeaf: true,
},
];
function updateTreeData(list: TreeNodeData[], key: string | undefined, children: TreeNodeData[]): TreeNodeData[] {
return list.map((node) => {
if (node.key === key) {
return { ...node, children };
}
if (node.children) {
return { ...node, children: updateTreeData(node.children, key, children) };
}
return node;
});
}
export default function TreeSelectDemo() {
const [treeData, setTreeData] = createSignal<TreeNodeData[]>(initialData);
function onLoadData(treeNode?: TreeNodeData) {
return new Promise<void>((resolve) => {
if (!treeNode || treeNode.children) {
resolve();
return;
}
const key = treeNode.key;
setTimeout(() => {
setTreeData((origin) =>
updateTreeData(origin, key, [
{
label: 'Child Node',
key: `${key}-0`,
},
{
label: 'Child Node',
key: `${key}-1`,
},
])
);
resolve();
}, 1000);
});
}
return <TreeSelect loadData={onLoadData} treeData={treeData()} style={{ width: '300px' }} placeholder="请选择" />;
}Custom Trigger
If the default trigger style cannot meet your needs, you can use triggerRender to customize the display of the select box. The input is a live object: read its fields in the returned JSX instead of destructuring it.
The triggerRender input is as follows:
interface TriggerRenderProps {
componentProps: Omit<TreeSelectProps, 'ref'>; // all props passed to TreeSelect
disabled: boolean; // disabled status
value: TreeNodeData[]; // data of the selected node
inputValue: string; // value of the input box
placeholder?: string; // placeholder
// Clears the value; pass the click event when bound to a control inside
// the trigger, so that the click does not also open the dropdown
onClear: (e?: MouseEvent) => void;
// Called when deleting a single item, with the key of the item
onRemove: (key: string) => void;
// Starts the search when the value of your own Input is updated;
// filterTreeNode must be non-false and searchPosition must be 'trigger'
onSearch: (inputValue: string) => void;
}
Code
import { Tag, TagInput, TreeSelect, type TreeNodeData, type TreeSelectTriggerRenderProps } from '@fibrous/semi-ui-solid';
const treeData: TreeNodeData[] = [
{
label: '亚洲',
value: '亚洲',
key: '0',
children: [
{
label: '中国',
value: '中国',
key: '0-0',
children: [
{
label: '北京',
value: '北京',
key: '0-0-0',
},
{
label: '上海',
value: '上海',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: '北美洲',
key: '1',
},
];
// The render props are a live object: read them in the returned JSX so the TagInput follows the selection
function renderTrigger(props: TreeSelectTriggerRenderProps) {
return (
<TagInput
value={props.value.flatMap<string>((item) => item.key ?? [])}
inputValue={props.inputValue}
onInputChange={props.onSearch}
renderTagItem={(key) => (
<Tag style={{ 'margin-left': '2px' }} tagKey={key} closable onClose={() => props.onRemove(key)}>
{props.value.find((item) => item.key === key)?.label}
</Tag>
)}
/>
);
}
export default function TreeSelectDemo() {
return <TreeSelect triggerRender={renderTrigger} filterTreeNode searchPosition="trigger" multiple treeData={treeData} placeholder="Custom Trigger" onChange={(value) => console.log('onChange', value)} style={{ width: '300px' }} />;
}Custom Rendering Selected Item
You can use renderSelectedItem to customize the rendering structure of the selected item in the selection box.
- In not multiple mode:
renderSelectedItem(treeNode: TreeNodeData) => content: JSX.Element - In multiple mode:
renderSelectedItem(treeNode: TreeNodeData, { index: number | string, onClose: (tagContent, e?) => void }) => { isRenderInTag: boolean, content: JSX.Element }- When isRenderInTag is true, content wraps are automatically rendered in the Tag (with background color and close button)
- When isRenderInTag is false, the returned content will be rendered directly
单选
多选+ isRenderInTag=true
多选 + isRenderInTag=false
Code
import { Tag, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-solid';
const treeData: TreeNodeData[] = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
{
label: '南美洲',
value: 'South America',
key: '2',
},
{
label: '南极洲',
value: 'Antarctica',
key: '3',
},
];
export default function TreeSelectDemo() {
return (
<>
<h4>单选</h4>
<TreeSelect style={{ width: '300px' }} treeData={treeData} renderSelectedItem={(item) => item.label} />
<h4>多选+ isRenderInTag=true</h4>
<TreeSelect style={{ width: '300px' }} treeData={treeData} multiple renderSelectedItem={(item) => ({ content: item.label, isRenderInTag: true })} />
<h4>多选 + isRenderInTag=false</h4>
<TreeSelect
style={{ width: '300px' }}
treeData={treeData}
multiple
maxTagCount={2}
renderSelectedItem={(item, { onClose }) => ({
content: (
<Tag color="white" closable onClose={onClose}>
{item.value}
</Tag>
),
isRenderInTag: false,
})}
/>
</>
);
}API Reference
TreeSelect
Props
| Property | Description | Type | Default |
|---|---|---|---|
| aria-label | Accessible name of the combobox: the search input while it is in the trigger, otherwise the trigger. | string | - |
| arrowIcon | Custom dropdown arrow icon on the right; null shows no arrow. With showClear on and a value selected, hovering shows the clear icon first. | JSX.Element | - |
| autoAdjustOverflow | Whether the popup flips its direction automatically when it is covered. | boolean | true |
| autoExpandParent | Whether parent nodes expand automatically. | boolean | false |
| autoMergeValue | Whether to merge the value: when on, selecting a parent node keeps its descendants out of the value. Works only when leafOnly is false. | boolean | true |
| borderless | Whether to use the borderless style. | boolean | false |
| checkRelation | In multiple mode, the relationship between the checked states of nodes: related or unRelated. With unRelated, the checked states of nodes do not affect each other. | CheckRelation | "related" |
| clearIcon | Custom icon of the clear button, effective when showClear is true. | JSX.Element | - |
| clickToHide | Whether the dropdown closes automatically after a selection; only works in single mode. | boolean | true |
| clickTriggerToHide | When the panel is open, whether clicking the trigger closes it. | boolean | true |
| defaultExpandAll | Whether to expand all nodes on initialization. After treeData changes this prop no longer takes effect; use expandAll if you need that. | boolean | - |
| defaultExpandedKeys | Keys of the nodes expanded by default. Their direct children are displayed. | string[] | - |
| defaultOpen | Whether the dropdown is open by default. | boolean | false |
| defaultValue | The initially selected value, read once on mount; an array in multiple mode. | TypeModeValue<T, Multiple> | - |
| disabled | Whether the component is disabled. | boolean | - |
| disableStrictly | Strict disabling: when a node is disabled, its checked state cannot be changed through its parent or child nodes. | boolean | false |
| dropdownClassName | Class name of the dropdown panel. | string | - |
| dropdownMatchSelectWidth | Whether the minimum width of the dropdown panel matches the width of the select box. | boolean | true |
| dropdownStyle | Style of the dropdown panel. | JSX.CSSProperties | string | - |
| emptyContent | Empty state shown when there is no data or the search finds no result. Without it the locale text is shown; null hides it. | JSX.Element | - |
| expandAction | How a node expands: false (only the expand icon expands it), click or doubleClick. | ExpandAction | false |
| expandAll | Whether to expand all nodes by default. The expansion still follows this prop after treeData changes. | boolean | false |
| expandedKeys | (Controlled) Keys of the expanded nodes. Their direct children are displayed. | string[] | - |
| expandIcon | Custom expand icon: an element or a function. An element gets the switcher class and the expand click from the component; a function receives class, onClick and expanded, and renders the switcher itself, attaching them to its element. | TreeProps['expandIcon'] | - |
| filterTreeNode | Whether the component is searchable, or a function that customizes the search; its third argument is the node data data. | Typeboolean | ((inputValue: string, treeNodeString: string, data?: TreeNodeData) => boolean) | false |
| icon | Custom node icon, as Tree's icon. An element is used for every node; a function is called once per row with the row's props, including its node data, and returns that row's icon. | TypeJSX.Element | ((row: TreeRowProps) => JSX.Element) | - |
| insetLabel | A label inside the select box, which also names the dropdown tree. | JSX.Element | - |
| insetLabelId | The id of the element around insetLabel, for aria-labelledby to point at. | string | - |
| keyMaps | Custom names of the key, label, value, disabled, children, isLeaf and icon fields in a node. If you rename the label field and enable search, set treeNodeFilterProp to one of the fields in treeData, or pass a custom search function to filterTreeNode. | KeyMapProps | - |
| labelEllipsis | Whether labels are truncated with an ellipsis on overflow. Without it, it is true when virtualized and false otherwise. | boolean | - |
| leafOnly | In multiple mode, whether only leaf nodes are displayed as tags, and the values passed to onChange are leaf nodes only. | boolean | - |
| loadData | Loads child nodes asynchronously and returns a Promise. Mark leaf nodes with isLeaf in treeData. | Type(treeNode?: TreeNodeData) => Promise<void> | - |
| loadedKeys | (Controlled) Keys of the nodes that have finished loading, used together with loadData. | string[] | - |
| maxTagCount | Maximum number of tags displayed; the rest are shown as +N. | number | - |
| motion | Whether the dropdown animates in and out. | boolean | true |
| motionExpand | Whether expanding and collapsing nodes animates. | boolean | true |
| multiple | Whether several nodes can be selected. | Multiple | false |
| onBlur | Called when the TreeSelect loses focus, once after each onFocus. Focus leaving the trigger and the dropdown passes a native FocusEvent, a click outside a native MouseEvent, and selecting a node that closes the dropdown the click or key event of that selection. | Type(e: MouseEvent | KeyboardEvent | FocusEvent) => void | - |
| onChange | Called when the selected value changes, with the value of the node (an array in multiple mode), the node data and the event. The event is null when a tag is closed and a KeyboardEvent when a node is selected from the keyboard; clearing a single selection passes undefined. With onChangeWithObject set to true, the arguments become the node data and the event. | Type(...args: OnChangeArgs<T, Multiple, WithObject>) => void | - |
| onChangeWithObject | Whether onChange receives all properties of the node. When true, the arguments of onChange become (node, e). | WithObject | false |
| onClear | Called when the clear button is clicked. | Type(e: MouseEvent) => void | - |
| onExpand | Called when a node expands or collapses, with the array of expanded keys and { expanded, node }. | Type(expandedKeys: string[], expandedOtherProps: ExpandedOtherProps) => void | - |
| onFocus | Called when focus enters the trigger (including its search input and clear button) or the dropdown from outside, with the native FocusEvent; moving focus among them does not call it again. Opening again with a click or key after a selection closed the dropdown also calls it, with that click or key event, and the focus searchAutoFocus gives on mount passes null. | Type(e: MouseEvent | KeyboardEvent | FocusEvent | null) => void | - |
| onLoad | Called when a node has finished loading. | Type(loadedKeys: Set<string>, treeNode: TreeNodeData) => void | - |
| onSearch | Called when the search value changes, with the search value, filteredExpandedKeys (keys of the nodes expanded by the search or by the value, useful when the expansion is controlled) and filteredNodes (the nodes that match the search). | Type(searchValue: string, filteredExpandedKeys: string[], filteredNodes: TreeNodeData[]) => void | - |
| onSelect | Called when a node is selected or deselected, with the key of the node, whether it is selected, and the node data. | Type(selectedKey: string, selected: boolean, selectedNode: TreeNodeData) => void | - |
| onVisibleChange | Called when the dropdown panel is shown or hidden, with whether it is visible. | Type(isVisible: boolean) => void | - |
| optionListStyle | Style of the option list. | JSX.CSSProperties | string | - |
| outerBottomSlot | Custom content rendered at the bottom of the dropdown panel, at the same level as the option list. | JSX.Element | - |
| outerTopSlot | Custom content rendered at the top of the dropdown panel, at the same level as the option list. With filterTreeNode on, it replaces the search box; to customize the search, use the search method through ref. | JSX.Element | - |
| placeholder | Placeholder of the input box. | string | - |
| position | Position of the popup; the values follow the position of Tooltip. Defaults to bottomLeft (bottomRight in RTL). | Position | - |
| prefix | Content in front of the select box. | JSX.Element | - |
| preventScroll | Whether the browser avoids scrolling the document to show the newly focused element when the component calls focus internally. It does not apply to elements passed in by the user. | boolean | - |
| ref | The root element, which carries the search and close methods; its type is TreeSelectElement. Its focus() focuses the combobox (the search input while it is in the trigger) without opening the dropdown. | TypeRef<TreeSelectElement> | - |
| remote | Whether remote search is enabled. When enabled, input skips local filtering and only triggers onSearch; the caller fetches the data and updates treeData. | boolean | false |
| renderFullLabel | Custom rendering of the whole row. It receives a live object, and the returned element is wrapped in a row element that carries role="treeitem" and the state attributes. Usage is the same as Tree's renderFullLabel. | Type(renderFullLabelProps: RenderFullLabelProps) => JSX.Element | - |
| renderLabel | Custom rendering of the node label. It receives the original label, the node data and the search word. | Type(label?: string | number, treeNode?: TreeNodeData, searchWord?: string) => JSX.Element | - |
| renderSelectedItem | Custom rendering of the selected items in the select box. In single mode it returns the content; in multiple mode it returns { content, isRenderInTag }, and when isRenderInTag is true the content is wrapped in a Tag with a background color and a close button. | TypeByMultiple<Multiple, RenderSelectedItemInSingle, RenderSelectedItemInMultiple> | - |
| restTagsPopoverProps | Popover configuration for the collapsed tags beyond maxTagCount; see Popover. | PopoverProps | - |
| searchAutoFocus | Whether the search box is focused on mount. | boolean | false |
| searchPlaceholder | Placeholder of the search box in the dropdown. | string | - |
| searchPosition | Position of the search box: dropdown or trigger. | 'dropdown' | 'trigger' | "dropdown" |
| searchRender | Custom search box. It receives a live object whose ref and ARIA attributes belong on the input; false renders no search box. | Typeboolean | ((inputProps: SearchRenderProps) => JSX.Element) | - |
| showClear | Whether the trigger shows the clear button when the value is not empty. | boolean | false |
| showFilteredOnly | Whether only the filtered results are displayed while searching. | boolean | - |
| showLine | Whether the nodes in the option panel show connecting lines. | boolean | - |
| showRestTagsPopover | When the number of tags exceeds maxTagCount, whether hovering +N shows the remaining tags in a Popover. | boolean | false |
| showSearchClear | Whether the search box in the dropdown can be cleared. | boolean | true |
| size | Size of the input box: large, small or default. | Size | "default" |
| stopPropagation | Whether click events on the dropdown panel stop bubbling. | boolean | string | true |
| style | Inline style of the trigger. Object keys use kebab-case, such as 'margin-right'. | JSX.CSSProperties | string | - |
| suffix | Content after the select box. | JSX.Element | - |
| treeData | Node data; keys are unique across the tree. Only a new array updates the options, changes made in place are not seen. | TreeNodeData[] | - |
| treeNodeFilterProp | Property of TreeNodeData matched by search. | string | "label" |
| treeNodeLabelProp | Property of TreeNodeData used to display the text. | string | "label" |
| triggerRender | Custom trigger. It receives a TriggerRenderProps live object; read its fields in the returned JSX. | Type(props: TriggerRenderProps) => JSX.Element | - |
| triggerTagWrap | Whether selected tags wrap onto multiple lines within the trigger. Only works when multiple and search are enabled and searchPosition is trigger. | boolean | false |
| validateStatus | Validation status: warning, error or default. It only affects the background color of the component. | ValidateStatus | - |
| value | (Controlled) The selected value. Passing it makes the component controlled, used together with onChange; an array in multiple mode. | TypeModeValue<T, Multiple> | - |
| virtualize | Virtual list configuration: an object with itemSize (required, the height of each row), height (the height of the dropdown, a number recommended) and width. Animation is disabled when virtualized. | Virtualize | - |
Methods
| Method | Description | Type |
|---|---|---|
| close | Closes the dropdown. | Type() => void |
| search | Searches as if the value were typed, opening the dropdown first. Needs filterTreeNode. | Type(value: string) => void |
class, style and native attributes such as id and data-* land on the root element (the trigger). aria-label, aria-labelledby, aria-describedby, aria-errormessage, aria-invalid and aria-required land on the current combobox: the root element when the TreeSelect is not searchable, or the search input when it is in the trigger. onFocus, onBlur, onChange and onSelect are the component's own callbacks and are not bound to the root element as native events.
TreeNodeData
The key of each
TreeNodeDatais required and must be unique.labelmay repeat.valueis optional. In that case the value read by onChange, value, defaultValue and onChangeWithObject becomes the key. To keep the behavior predictable, either leave everyvaluein treeData unset, or set every one of them and keep them unique; mixing the two is not recommended.
| Properties | Instructions | type | Default |
|---|---|---|---|
| value | Value of the node | string|number | - |
| label | Text displayed; use renderLabel for custom content | string|number | - |
| disabled | Whether the node is disabled, in multi-choice | boolean | false |
| key | required and must be unique | string | - |
| isLeaf | Whether the node is a leaf node | boolean | - |
| children | Child nodes | TreeNodeData[] | - |
The icon of a node comes from the TreeSelect icon prop and is not declared in the data: an element gives every node the same icon, and a function is called once per row with the row's props (including its node data).
Methods
The ref of TreeSelect gets the root element (the trigger), which carries the methods. Its type is TreeSelectElement (that is, HTMLDivElement & TreeSelectHandle).
| Name | Description |
|---|---|
| search(value: string) | To customize the search box outside, call this method whenever its value changes to update the filtered result. It searches as if the value were typed and opens the dropdown first; it needs filterTreeNode |
| close() | Closes the dropdown |
import { TreeSelect, type TreeSelectElement } from '@fibrous/semi-ui-solid';
function App() {
let treeSelect: TreeSelectElement | undefined;
return (
<>
<TreeSelect ref={treeSelect} filterTreeNode />
<button onClick={() => treeSelect?.close()}>Close</button>
</>
);
}
Accessibility
ARIA
- Following the ARIA 1.2 combobox pattern, exactly one element is the combobox. Its name comes from, in order of priority:
aria-labelledby,aria-label, the rendered insetLabel (#insetLabelin Vue; withoutinsetLabelIdthe component generates the id; with a prefix the insetLabel is not rendered and does not name it), and otherwise the name in the locale:- Without search, or with
searchPosition="dropdown", the trigger is a select-only combobox. The search input in the dropdown stays a text box witharia-controls,aria-autocompleteandaria-activedescendant - With
searchPosition="trigger", the search input is the combobox and the only Tab stop, witharia-autocomplete="list"; the trigger has no role. In single mode the input is empty until the user types, so the selected text is linked to it as its description (aria-describedby). Clicking anywhere on the trigger moves focus to the input;
- Without search, or with
- TreeSelect allows users to set
aria-describedby,aria-errormessage,aria-invalid,aria-labelledby,aria-required, in addition, Form will automatically set these properties for Form.TreeSelect; - The
role="tree"list in the dropdown uses the same name source as the combobox: the samearia-labelledbyids, the samearia-labelor the same insetLabel; with none of them it takes the name in the locale, like the combobox;
- Nodes in the dropdown follow the same pattern as Tree:
role="treeitem", witharia-level,aria-setsize,aria-posinsetandaria-disabled; expandable nodes carryaria-expanded. Single-choice usesaria-selected, multi-choice usesaria-checked(mixedwhen partially checked).
- The expand arrow and the checkbox in front of a node only picture its state: they are hidden from screen readers and take no focus.
Keyboard Interaction
TreeSelect follows the WAI-ARIA Combobox pattern with a tree popup: focus always stays on the trigger or the search input, aria-activedescendant points at the current node, and the current node shows the focus ring. There is no current node when the dropdown opens.
- While the dropdown is closed:
ArrowDown,ArrowUp,EnterandSpaceopen it;HomeandEndopen it and move to the first or last visible node ArrowDown,ArrowUp: move to the next or previous visible node; the firstArrowDownmoves to the first node;Home,End: move to the first or last visible nodeArrowRight: expand a collapsed node; on an expanded node, move to its first child (swapped withArrowLeftin RTL)ArrowLeft: collapse an expanded node; otherwise move to the parentEnter,Space: select the current node, or check and uncheck it in a multi-choice TreeSelect; disabled nodes do not respond- Typing characters: while the dropdown is open, move to the next visible node after the current one whose label starts with the typed text; characters typed in quick succession form one search string. A closed dropdown ignores them
Esc: close the dropdown
While focus is in a search input, only ArrowDown, ArrowUp and Enter move and select; the other keys (including characters, Space, Home, End, ArrowLeft and ArrowRight) edit the text.
With showClear, a selected value or search text, and no disabled, the trigger renders a clear button. It is a native button named "Clear TreeSelect value" from the locale, shown on hover, while the dropdown is open, or while focus is inside the TreeSelect. From the trigger or the search input, Tab moves to the clear button; Enter or Space clears, as a mouse click does, and the focus goes back to the trigger or the search input. In multiple mode Backspace in the search input also removes tags.
The input of a custom searchRender is a live object that includes these ARIA attributes (aria-activedescendant, aria-controls, aria-autocomplete and the name; on the trigger, the whole set of combobox attributes including role and aria-expanded). Spread them onto the input, otherwise screen readers will not announce the current node. Its ref is a callback that must also go on the input (a Solid Input, a native input or a textarea), so that a click on a selected item inside the trigger can hand focus to it.
Demo:
<TreeSelect aria-label="example treeSelect" treeData={treeData} />
Design Tokens
| Sass variable | Value | Usage |
|---|---|---|
| $color-treeSelect_default-bg-default | var(--semi-color-fill-0) | 树选择器选择框背景颜色 - 默认 |
| $color-treeSelect_default-bg-hover | var(--semi-color-fill-1) | 树选择器选择框背景颜色 - 悬停 |
| $color-treeSelect_default-bg-active | var(--semi-color-fill-2) | 树选择器选择框背景颜色 - 按下 |
| $color-treeSelect_default-bg-focus | var(--semi-color-fill-0) | 树选择器选择框背景颜色 - 选中 |
| $color-treeSelect_default-border-default | transparent | 树选择器选择框描边颜色 - 默认 |
| $color-treeSelect_selection-text-default | var(--semi-color-text-0) | 树选择器选择框回填内容文本颜色 - 默认 |
| $color-treeSelect_default-icon-default | var(--semi-color-text-2) | 树选择器选择框图标颜色 - 默认 |
| $color-treeSelect_default-icon-hover | var(--semi-color-primary-hover) | 树选择器选择框清空按钮颜色 - 悬停 |
| $color-treeSelect_default-icon-active | var(--semi-color-primary-active) | 树选择器选择框清空按钮颜色 - 按下 |
| $color-treeSelect_default-border-hover | transparent | 树选择器选择框描边颜色 - 悬浮 |
| $color-treeSelect_default-border-focus | var(--semi-color-focus-border) | 树选择器选择框描边颜色 - 选中 |
| $color-treeSelect_search-border-default | var(--semi-color-fill-0) | 树选择器菜单搜索框描边颜色 - 默认 |
| $color-treeSelect_tag_disabled-bg-default | transparent | 禁用树选择器菜单标签背景颜色 |
| $color-treeSelect_input_disabled-bg-default | var(--semi-color-disabled-fill) | 禁用树选择器选择框背景颜色 |
| $color-treeSelect_input_disabled-text-default | var(--semi-color-disabled-text) | 禁用树选择器选择框文本颜色 |
| $color-treeSelect_input_disabled-bg-hover | var(--semi-color-disabled-fill) | 禁用树选择器选择框背景颜色 - 悬浮 |
| $color-treeSelect_input_placeholder-text-default | var(--semi-color-text-2) | 树选择器选择框占位文本颜色 |
| $color-treeSelect_warning-bg-default | var(--semi-color-warning-light-default) | 警告树选择器选择框背景颜色 - 默认 |
| $color-treeSelect_warning-border-default | var(--semi-color-warning-light-default) | 警告树选择器选择框描边颜色 - 默认 |
| $color-treeSelect_warning-bg-hover | var(--semi-color-warning-light-hover) | 警告树选择器选择框背景颜色 - 悬浮 |
| $color-treeSelect_warning-border-hover | var(--semi-color-warning-light-hover) | 警告树选择器选择框描边颜色 - 悬浮 |
| $color-treeSelect_warning-bg-focus | var(--semi-color-warning-light-default) | 警告树选择器选择框背景颜色 - 选中 |
| $color-treeSelect_warning-border-focus | var(--semi-color-warning) | 警告树选择器选择框描边颜色 - 选中 |
| $color-treeSelect_warning-bg-active | var(--semi-color-warning-light-active) | 警告树选择器选择框背景颜色 - 激活 |
| $color-treeSelect_warning-border-active | var(--semi-color-warning-light-active) | 警告树选择器选择框描边颜色 - 激活 |
| $color-treeSelect_danger-bg-default | var(--semi-color-danger-light-default) | 错误树选择器选择框背景颜色 - 默认 |
| $color-treeSelect_danger-border-default | var(--semi-color-danger-light-default) | 错误树选择器选择框描边颜色 - 默认 |
| $color-treeSelect_danger-bg-hover | var(--semi-color-danger-light-hover) | 错误树选择器选择框背景颜色 - 悬浮 |
| $color-treeSelect_danger-border-hover | var(--semi-color-danger-light-hover) | 错误树选择器选择框描边颜色 - 悬浮 |
| $color-treeSelect_danger-bg-focus | var(--semi-color-danger-light-default) | 错误树选择器选择框背景颜色 - 选中 |
| $color-treeSelect_danger-border-focus | var(--semi-color-danger) | 错误树选择器选择框描边颜色 - 选中 |
| $color-treeSelect_danger-bg-active | var(--semi-color-danger-light-active) | 错误树选择器选择框背景颜色 - 激活 |
| $color-treeSelect_danger-border-active | var(--semi-color-danger-light-active) | 错误树选择器选择框描边颜色 - 激活 |
| $radius-treeSelect | var(--semi-border-radius-small) | 树选择器圆角 |
| $width-treeSelect-border | 1px | 树选择器描边宽度 |
| $width-treeSelect_search_wrapper-border | 1px | 树选择器搜索框描边宽度 |
| $width-treeSelect_hover-border | $border-thickness-control-focus | 树选择器选择框描边宽度 - 悬浮 |
| $width-treeSelect_focus-border | $width-treeSelect_hover-border | 树选择器选择框描边宽度 - 选中 |
| $width-treeSelect_default | 80px | 树选择器最小宽度 |
| $height-treeSelect_default | $height-control-default | 树选择器选择器高度 - 默认 |
| $font-treeSelect_default-lineHeight | $height-treeSelect_default | 树选择器选择器文本行高 |
| $font-treeSelect_default-fontWeight | $font-weight-regular | 树选择器选择器文本字重 |
| $height-treeSelect_small | $height-control-small | 小尺寸树选择器选择器高度 |
| $font-treeSelect_small-lineHeight | $height-treeSelect_small | 小尺寸树选择器选择器文本行高 |
| $height-treeSelect_large | $height-control-large | 大尺寸树选择器选择器文本行高 |
| $font-treeSelect_large-lineHeight | $height-treeSelect_large | 大尺寸树选择器选择器文本行高 |
| $font-treeSelect_prefix_suffix_fontWeight | $font-weight-bold | 树选择器前缀后缀文本字重 |
| $spacing-treeSelect_selection_tagInput_wrapper-paddingX | $spacing-extra-tight | 树选择器多选标签容器水平内边距 |
| $spacing-treeSelect_selection_tagInput_empty-marginLeft | $spacing-extra-tight | 树选择器多选标签容器为空时左侧外边距 |
| $spacing-treeSelect_selection_tagInput_notEmpty-marginLeft | -$spacing-extra-tight | 树选择器多选标签容器不为空时左侧外边距 |
| $spacing-treeSelect_selection-paddingLeft | $spacing-base-tight | 树选择器单选左侧内边距 |
| $spacing-treeSelect_tag-marginX | $spacing-super-tight | 树选择器多选标签水平外边距 |
| $spacing-treeSelect_tag-marginY | 1px | 树选择器多选标签垂直外边距 |
| $spacing-treeSelect_selection_multiple-paddingLeft | 4px | 树选择器多选标签左侧内边距 |
| $spacing-treeSelect_placeholder_multiple-paddingLeft | 8px | 树选择器多选占位文本左侧外边距 |
| $spacing-treeSelect_prefix_text-marginY | 0px | 树选择器前缀文本垂直外边距 |
| $spacing-treeSelect_prefix_text-marginX | $spacing-base-tight | 树选择器前缀文本水平外边距 |
| $spacing-treeSelect_prefix_icon-marginY | 0px | 树选择器前缀图标垂直外边距 |
| $spacing-treeSelect_prefix_icon-marginX | $spacing-tight | 树选择器前缀图标水平外边距 |
| $spacing-treeSelect_selection_withSuffix-paddingRight | 0px | 树选择器有后缀时内容右侧内边距 |
| $color-treeSelect_selection_TriggerSearchItem_disabled-text-default | var(--semi-color-disabled-text) | 带搜索的树选择器触发器占位文本默认颜色 |
| $color-treeSelect_inputTrigger-border-default | none | 带搜索的树选择器触发器描边颜色 |
| $color-treeSelect_inputTrigger-bg-default | transparent | 带搜索的树选择器触发器背景颜色 |
| $color-treeSelect_prefix_suffix_text-default | var(--semi-color-text-2) | 带搜索的树选择器前后缀文本颜色 |
| $width-treeSelect_arrow | 32px | 树选择器展开箭头宽度 |
| $width-treeSelect_option | 230px | 树选择器菜单项宽度 |
| $height-treeSelect_popover | 300px | 树选择器菜单高度 |
| $height-treeSelect_selection_tagInput_wrapper_small | 22px | 树选择器多选搜索,搜索框在选择框时选择框最小高度 - 小尺寸 |
| $height-treeSelect_selection_tagInput_wrapper_default | 30px | 树选择器多选搜索,搜索框在选择框时选择框最小高度 - 默认尺寸 |
| $height-treeSelect_selection_tagInput_wrapper_large | 38px | 树选择器多选搜索,搜索框在选择框时选择框最小高度 - 大尺寸 |