@douyinfe/semi-ui
Version:
A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.
1,629 lines (1,503 loc) • 85.1 kB
Markdown
---
localeCode: en-US
order: 36
category: Input
title: Cascader
subTitle: Cascade
icon: doc-cascader
brief: Used to select an option under a multi-level classification.
---
## Usage scenarios
Differences from TreeSelect component:
- TreeSelect: The core value lies in **target node**. The structure is to facilitate users to quickly filter out target options. The final node is what the user wants. It is commonly used in file/folder selection, organizational structure, permission allocation and other scenarios.
- Cascader: The core selection value lies in the **path**. What the user selects is not an isolated point, but a complete path from root to leaf, which is often used in scenarios such as geographical location and product classification.
## Demos
### How to import
```jsx import
import { Cascader } from '@douyinfe/semi-ui';
```
### Basic Usage
Basic usage, only leaf nodes can be selected by default.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 400 }}
treeData={treeData}
placeholder="Please select"
/>
);
};
```
### Multiple
Set `multiple` to make multiple selections.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
defaultValue= {['impressionism', 'visualArts', 'Monet']}
style={{ width: 400 }}
treeData={treeData}
placeholder="Please select"
multiple
/>
);
};
```
### Searchable
Use `filterTreeNode` to support search input.
By default, the `label` value is searched (using the includes method of the string for matching, case-insensitive). You can specify other attribute values through `treeNodeFilterProp` to search. For example, If `label` is ReactNode, you can use other fields in treeData to store plain text, and specify the field for search through `treeNodeFilterProp`.
The default search results will only display the paths of leaf nodes. If you want to display more results, you can set `filterLeafOnly` to `false`.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
const labelNodeTreeData = [{
label: <Tooltip content="Other info">Impressionism</Tooltip>,
labelText: 'Impressionism',
value: 'impressionism',
children: [
{
label: <Tooltip content="Other info">Visual Arts</Tooltip>,
labelText: 'Visual Arts',
value: 'visualArts',
children: [
{
label: <Tooltip content="Other info">Claude Monet</Tooltip>,
labelText: 'Claude Monet',
value: 'Monet',
},
{
label: <Tooltip content="Other info">'Pierre-Auguste Renoir</Tooltip>,
labelText: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: <Tooltip content="Other info">Édouard Manet</Tooltip>,
labelText: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: <Tooltip content="Other info">Music</Tooltip>,
labelText: 'Music',
value: 'music',
children: [
{
label: <Tooltip content="Other info">Claude Debussy</Tooltip>,
labelText: 'Claude Debussy',
value: 'Debussy',
},
{
label: <Tooltip content="Other info">Maurice Ravel</Tooltip>,
labelText: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<div>
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Search in label by default"
filterTreeNode
/>
<br/>
<br/>
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Search in value"
filterTreeNode
treeNodeFilterProp='value'
/>
<br/>
<br/>
<Typography.Title heading={6}>filterLeafOnly=false:</Typography.Title>
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="filterLeafOnly=false"
filterTreeNode
filterLeafOnly={false}
/>
<br/>
<br/>
<Typography.Title heading={6}>Label is ReactNode, specify other attributes to search</Typography.Title>
<Cascader
style={{ width: 300 }}
treeData={labelNodeTreeData}
placeholder="Search for labelText"
filterTreeNode
treeNodeFilterProp='labelText'
/>
</div>
);
};
```
### Searchable Multiple Selection
When multiple selection and search are supported at the same time, in this scenario, you can delete the corresponding selected item by pressing the BackSpace key.
```jsx live=true
import React, { useState } from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const [value, setValue] = useState(['impressionism', 'visualArts', 'Monet']);
const onChange = (newValue) => {
setValue(newValue);
};
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please select"
value={value}
multiple
filterTreeNode
onChange={onChange}
/>
);
};
```
Filtered data can be sorted using `filterSorter`, `filterSorter` is available since v2.28.0.
```jsx live=true
import React, { useState } from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Product',
value: 'Product',
children: [
{
label: 'Semi-Material',
value: 'Semi-Material',
},
{
label: 'Semi-DSM',
value: 'Semi-DSM',
},
{
label: 'Semi',
value: 'Semi',
},
{
label: 'Semi-C2D',
value: 'Semi-C2D',
},
{
label: 'Semi-D2C',
value: 'Semi-D2C',
},
],
}
];
return (
<div>
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Enter s to view the sorting effect"
filterTreeNode
filterSorter={(first, second, inputValue) => {
const firstData = first[first.length - 1];
const lastData = second[second.length - 1];
if (firstData.label === inputValue) {
return -1;
} else if (lastData.label === inputValue) {
return 1;
} else {
return firstData.label < lastData.label ? -1 : 1;
}
}}
/>
</div>
);
};
```
If you want to customize the rendering options after the search, you can use `filterRender` to achieve custom rendering of the entire line. The `filterRender` is available since v2.28.0, parameters are as follows:
``` tsx
interface filterRenderProps {
className: string;
inputValue: string; // Search bar search content
disabled: boolean; // Whether to disable
data: CascaderData[]; // Search result data
selected: boolean; // Selected state when single selection
checkStatus: { // Checked state when multiple selection
checked: boolean;
halfChecked: boolean;
};
onClick: (e: React.MouseEvent) => void; // Callback when clicked option in single selection
onCheck: (e: React.MouseEvent) => void; // Callback when clicked option in multiple selection
}
```
The example is as follows
```jsx live=true
import React, { useState } from 'react';
import { Cascader, Typography, Checkbox } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Semi',
value: 'Semi',
children: [
{
label: 'Semi-Material Semi-Material Semi-Material Semi-Material',
value: 'Semi-Material',
},
{
label: 'Semi-DSM Semi-DSM Semi-DSM Semi-DSM',
value: 'Semi-DSM',
},
{
label: 'Semi Design Semi Design Semi Design Semi Design',
value: 'Semi Design',
},
{
label: 'Semi-C2D Semi-C2D Semi-C2D Semi-C2D Semi-C2D',
value: 'Semi-C2D',
},
{
label: 'Semi-D2C Semi-D2C Semi-D2C Semi-D2C Semi-D2C ',
value: 'Semi-D2C',
},
],
}
];
const { Text } = Typography;
const renderSearchOptionSingle = (props) => {
const { className, data, onClick, onKeyPress, selected } = props;
return (
<li
className={className}
style={{ justifyContent: 'flex-start' }}
role="treeitem"
onClick={onClick}
onKeyPress={onKeyPress}
>
<Text
ellipsis={{ showTooltip: { opts: { style: { wordBreak: 'break-all' } } } }}
style={{ width: 270, color: selected ? 'var(--semi-color-primary)': undefined }}
>
{data.map(item => item.label ).join(' / ')}
</Text>
</li>
);
};
const renderSearchOptionMultiple = (props) => {
const { className, data, checkStatus, onClick, onKeyPress } = props;
return (
<li
className={className}
style={{ justifyContent: 'flex-start' }}
role="treeitem"
onClick={onCheck}
onKeyPress={onKeyPress}
>
<Checkbox
onChange={onCheck}
indeterminate={checkStatus.halfChecked}
checked={checkStatus.checked}
style={{ marginRight: 8 }}
/>
<Text
ellipsis={{ showTooltip: { opts: { style: { wordBreak: 'break-all' } } } }}
style={{ width: 250 }}
>
{data.map(item => item.label).join(' / ')}
</Text>
</li>
);
};
return (
<div>
<p>Mouse over the option to view the complete content of the omitted text</p>
<br />
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Single selection, enter s"
filterTreeNode
filterRender={renderSearchOptionSingle}
/>
<br />
<Cascader
multiple
style={{ width: 300, marginTop: 20 }}
treeData={treeData}
placeholder="Multiple selection, enter s"
filterTreeNode
filterRender={renderSearchOptionMultiple}
/>
</div>
);
};
```
If there are a lot of options in the search results, you can optimize performance by setting virtualizeInSearch to enable the virtualization of the search result panel. virtualizeInSearch has been available since v2.44.0. virtualizeInSearch is an object containing the following values:
- height: Option list height value
- width: Option list width value
- itemSize: The height of each row of Option
```jsx live=true
import React from 'react';
import { Cascader, Checkbox, Typography } from '@douyinfe/semi-ui';
() => {
const treeData = useMemo(() => (
['Generic', 'Scene'].map((label, m) => ({
label: label,
value: m,
children: new Array(100).fill(0).map((item, n)=> ({
value: `${m}-${n}`,
label: `${m}-${n} level one`,
children: new Array(20).fill(0).map((item, o)=> ({
value: `${m}-${n}-${o}`,
label: `${m}-${n}-${o} level two detail info`,
})),
}))
}))
), []);
let virtualize = {
// The height is the panel's default height of 180px minus the upper and lower padding 2 * 8px
height: 172,
width: 320,
itemSize: 36,
};
const filterRender = useCallback((props) => {
const { data, onCheck, checkStatus, className } = props;
return (
<div
key={data.value}
className={className}
style={{ justifyContent: 'start', padding: '8px 16px 8px 12px', boxSizing: 'border-box' }}
>
<Checkbox
onChange={onCheck}
indeterminate={checkStatus.halfChecked}
checked={checkStatus.checked}
style={{ marginRight: 8 }}
/>
<Typography.Text
ellipsis={{ showTooltip: { opts: { style: { wordBreak: 'break-all' } } } }}
style={{ maxWidth: 260 }}
>
{data.map(item => item.label).join(' | ')}
</Typography.Text>
</div>
);
}, []);
return (
<Cascader
multiple
filterTreeNode
style={{ width: 320 }}
treeData={treeData}
placeholder="Enter generic or scene to search"
virtualizeInSearch={virtualize}
filterRender={filterRender}
/>
);
};
```
### Limit Tags Displayed
When multiple selections, you can use `maxTagCount` to limit the number of tags displayed, and the excess will be displayed as +N.
You can use `showRestTagsPopover` to set whether hover +N displays Popover after maxTagCount is exceeded, the default is false. And, you can also configure Popover in the `restTagsPopoverProps` property.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please selection"
multiple
maxTagCount={1}
showRestTagsPopover={true}
restTagsPopoverProps={{ position: 'top' }}
defaultValue={[
['impressionism', 'visualArts', 'Monet'],
['impressionism', 'visualArts', 'Renoir']
]}
/>
);
};
```
### Limit Tags Number
In a multi-selection scene, use max to limit the number of multi-selection selections. After max is exceeded, the onExceed callback will be triggered.
```jsx live=true
import React from 'react';
import { Cascader, Toast } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please selection"
multiple
max={1}
onExceed={v=>{
Toast.warning('exceed max');
console.log(v);
}}
defaultValue={[
['impressionism', 'visualArts', 'Monet']
]}
/>
);
};
```
### Change on Select
In the case of single selection, you can also set `changeOnSelect` to allow the parent option to be selected.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<div>
<Cascader
style={{ width: 400 }}
treeData={treeData}
changeOnSelect
placeholder="Change on select"
/>
<br/>
<br/>
<Cascader
style={{ width: 400 }}
treeData={treeData}
changeOnSelect
placeholder="Searchable change on select"
filterTreeNode
/>
</div>
);
};
```
### Custom Display Property
Set `displayProp` to select which property in the data you would like to display. By default, `label` is displayed.
```jsx live=true
import React from 'react';
import { Cascader, Typography } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}
];
return (
<>
<Typography.Title heading={6}>single selection</Typography.Title>
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please Select"
displayProp='value'
defaultValue={['impressionism', 'visualArts', 'Monet']}
/>
<br />
<br />
<Typography.Title heading={6}>multiple selection</Typography.Title>
<Cascader
multiple
style={{ width: 300 }}
treeData={treeData}
defaultValue={['impressionism', 'visualArts', 'Monet']}
placeholder="Please Select"
displayProp='value'
/>
</>
);
};
```
The return format can be set by setting `displayRender`.
When single selection (`multiple=false`), `displayRender((labelPath: string[]) => ReactNode)`, where labelPath is a path array composed of labels.
When multiple selection (`multiple=true`), `displayRender((item: Entity, index: number) => ReactNode)`, where item is the relevant data of the node.
```typescript
interface Entity {
children?: Entity[]; // children list
data: CascaderData; // treedata
ind: number; // index
key: string; // key
level: number; // node level
parent?: Entity; // parent data
parentKey?: string; // parent key
path: string[]; // key path
valuePath: string[]; // value path
}
```
```jsx live=true
import React from 'react';
import { Cascader, Tag, Typography } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}
];
return (
<>
<Typography.Title heading={6}>single selection</Typography.Title>
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please select"
displayRender={list => 'Selected:' + list.join(' -> ')}
defaultValue={['impressionism', 'visualArts', 'Monet']}
/>
<br />
<br />
<Typography.Title heading={6}>multiple selection</Typography.Title>
<Cascader
multiple
style={{ width: 300 }}
treeData={treeData}
defaultValue={['impressionism', 'visualArts', 'Monet']}
placeholder="Please select"
displayRender={(item, idx) => (
<Tag
style={{ marginRight: 4 }}
color='white'
key={`${idx}-${item.data.label}`}
>
{item.data.label}
</Tag>
)}
/>
</>
);
};
```
### Custom Separator
Version: >=2.2.0
You can use `separator` to set the separator, including: the separator of the content displayed in the dropdown during search and displayed in the Trigger during single selection.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}
];
return (
<Cascader
style={{ width: 400 }}
treeData={treeData}
defaultValue={['impressionism', 'visualArts', 'Monet']}
filterTreeNode
separator=' > '
/>
);
};
```
### Disabled
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<div>
<Cascader
style={{ width: 400 }}
treeData={treeData}
placeholder="Please select"
disabled
/>
<br />
<br />
<Cascader
style={{ width: 400 }}
treeData={treeData}
placeholder="Please select"
defaultValue={['impressionism', 'music', 'Debussy']}
filterTreeNode
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 "Music" is strictly disabled. Therefore, when we change the selected state of its parent node "Impressionism", it will not affect the selected state of the node "Music".
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
disabled: true,
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
multiple
placeholder="Please select..."
disableStrictly
/>
);
};
```
### the Way of Expand Menu
You can use `showNext` to set the time to expand the Dropdown submenu, optional: `click` (default), `hover`.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 400 }}
treeData={treeData}
placeholder="Please select"
showNext="hover"
/>
);
};
```
### Click to Select
In multiple mode, clicking on non-leaf nodes does not trigger selection by default. You can use `clickToSelect` to enable selecting any node on click.
This API is especially useful when combined with `showNext="hover"`: hovering expands the submenu, while clicking selects the current node.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
],
},
],
}
];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
multiple
placeholder="Please select"
showNext="hover"
clickToSelect
/>
);
};
```
### Additional items
We have reserved slots at the top and bottom of the cascade selector. You can set them through bottomSlot or topSlot.
```jsx live=true
import React from 'react';
import { Cascader, Typography } from '@douyinfe/semi-ui';
() => {
const { Text } = Typography;
const slotStyle = {
height: '36px',
display: 'flex',
padding: '0 32px',
alignItems: 'center',
cursor: 'pointer',
borderTop: '1px solid var(--semi-color-border)'
};
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please select"
bottomSlot={
<div style={slotStyle}>
<Text>{`Can't find a relevant option?`}</Text>
<Text link>Go to create</Text>
</div>
}
/>
);
};
```
### Controlled Component
You can use `value` along with `onChange` property if you want to use Cascader as a controlled component.
```jsx live=true
import React, { useState } from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const [value, setValue] = useState([]);
const onChange = (newValue) => {
setValue(newValue);
};
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}];
return (
<Cascader
style={{ width: 400 }}
treeData={treeData}
placeholder="Please select"
value={value}
onChange={onChange}
/>
);
};
```
### Auto Merge Value
In the multi-selection (multiple=true) scenario, when we select the ancestor node, if we want the value not to include its corresponding descendant nodes, we can set it by `autoMergeValue`, and the default is true. When `autoMergeValue` and `leafOnly` are turned on at the same time, the latter has a higher priority.
```jsx live=true
import React, { useState } from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const [value, setValue] = useState(['impressionism', 'visualArts']);
const onChange = value => {
setValue(value);
};
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}
];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please select"
value={value}
multiple
autoMergeValue={false}
onChange={e => onChange(e)}
/>
);
};
```
### Leaf Only
version: >=2.2.0
In multiple selection, you can set the value to include only leaf nodes by turning on leafOnly, that is, the displayed Tag and onChange parameter values only include value.
```jsx live=true
import React, { useState } from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
const [value, setValue] = useState(['impressionism', 'visualArts']);
const onChange = value => {
setValue(value);
};
const treeData = [
{
label: 'Impressionism',
value: 'impressionism',
children: [
{
label: 'Visual Arts',
value: 'visualArts',
children: [
{
label: 'Claude Monet',
value: 'Monet',
},
{
label: 'Pierre-Auguste Renoir',
value: 'Renoir',
},
{
label: 'Édouard Manet',
value: 'Manet',
},
],
},
{
label: 'Music',
value: 'music',
children: [
{
label: 'Claude Debussy',
value: 'Debussy',
},
{
label: 'Maurice Ravel',
value: 'Ravel',
}
]
}
],
}
];
return (
<Cascader
style={{ width: 300 }}
treeData={treeData}
placeholder="Please select"
value={value}
multiple
leafOnly
onChange={e => onChange(e)}
/>
);
};
```
### Checked RelationShip
Version: >= 2.71.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.
```jsx live=true
import React from 'react';
import { Cascader } from '@douyinfe/semi-ui';
() => {
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: 'North America',
value: 'North America',
key: '1',
}
];
return (
<Cascader
multiple