| name | n-cascader |
| description | A cascader component for displaying and selecting tree-structured data with support for single/multiple selection, async loading, filtering, and various check strategies |
| author | jiaiyan |
| version | 1.0.0 |
n-cascader Component
The n-cascader component is used to display and select tree-structured data. It supports single and multiple selection modes, async data loading, filtering, and various check strategies for flexible selection behavior.
When to Use
Use n-cascader when you need to:
- Select from hierarchical data (e.g., region selection, category selection)
- Build multi-level navigation or selection interfaces
- Support both single and multiple selection in tree structures
- Load data asynchronously as users navigate
- Filter through large hierarchical datasets
- Display selected values as paths or individual items
Basic Usage
Single Selection
<template>
<n-cascader
v-model:value="value"
placeholder="Select option"
:options="options"
check-strategy="child"
@update:value="handleUpdateValue"
/>
</template>
<script setup>
import { ref } from 'vue';
const value = ref(null);
const options = [
{
label: 'Asia',
value: 'asia',
children: [
{
label: 'China',
value: 'china',
children: [
{ label: 'Beijing', value: 'beijing' },
{ label: 'Shanghai', value: 'shanghai' },
],
},
],
},
];
const handleUpdateValue = value => {
console.log(value);
};
</script>
Multiple Selection
<template>
<n-cascader
v-model:value="value"
multiple
placeholder="Select options"
clearable
:options="options"
cascade
check-strategy="all"
@update:value="handleUpdateValue"
/>
</template>
<script setup>
import { ref } from 'vue';
const value = ref([]);
const options = [];
</script>
Different Sizes
<template>
<n-space vertical>
<n-cascader
v-model:value="value"
placeholder="Small"
:options="options"
size="small"
/>
<n-cascader
v-model:value="value"
placeholder="Medium (default)"
:options="options"
size="medium"
/>
<n-cascader
v-model:value="value"
placeholder="Large"
:options="options"
size="large"
/>
</n-space>
</template>
API Reference
Props
| Name | Type | Default | Description |
|---|
value / v-model:value | string | number | Array<number | string> | null | undefined | Value of the cascader. |
allow-checking-not-loaded | boolean | false | Whether to allow cascade checking on not loaded nodes. |
cascade | boolean | true | Whether to cascade the checkbox selection onto children. |
check-strategy | 'all' | 'parent' | 'child' | 'all' | The way to show checked options. |
children-field | string | 'children' | The children field in CascaderOption. |
clearable | boolean | false | Whether the cascader is clearable. |
clear-filter-after-select | boolean | true | Whether to clear filter keyword after select. |
default-value | string | number | Array<number | string> | null | null | Default selected value. |
disabled | boolean | false | Whether to disable the cascader. |
disabled-field | string | 'disabled' | The disabled field in CascaderOption. |
ellipsis-tag-popover-props | PopoverProps | undefined | Popover props of the preview ellipsis tag. |
expand-trigger | 'click' | 'hover' | 'click' | Trigger for expanding options. |
filterable | boolean | false | Whether the cascader is filterable. |
filter | (pattern: string, option: CascaderOption, path: CascaderOption[]) => boolean | - | Filter function of the cascader. |
filter-menu-props | HTMLAttributes | undefined | The filter menu's DOM props. |
get-column-style | (detail: { level: number }) => string | object | undefined | Function that resolves column style. |
value-field | string | 'value' | The value field in CascaderOption. |
label-field | string | 'label' | The label field in CascaderOption. |
max-tag-count | number | 'responsive' | undefined | Max tag count in multiple select mode. |
menu-props | HTMLAttributes | undefined | The menu's DOM props. |
multiple | boolean | false | Whether to allow multiple selection. |
options | CascaderOption[] | [] | Options of the cascader. |
placeholder | string | 'Please Select' | Placeholder text. |
placement | 'top-start' | 'top' | ... | 'bottom-start' | Cascader placement. |
remote | boolean | false | Whether to obtain data remotely. |
render-prefix | (info: { option, node, checked }) => VNodeChild | undefined | Render function of options' prefix. |
render-label | (option: CascaderOption, checked: boolean) => VNodeChild | undefined | Render function for option label. |
render-suffix | (info: { option, node, checked }) => VNodeChild | undefined | Render function of options' suffix. |
scrollbar-props | ScrollbarProps | undefined | Scrollbar props. |
separator | string | ' / ' | Selected option path value separator. |
show | boolean | undefined | Whether to show the menu. |
show-path | boolean | true | Whether to show selected options as a path. |
size | 'small' | 'medium' | 'large' | 'medium' | Cascader size. |
spin-props | object | undefined | Loading icon properties. |
status | 'success' | 'warning' | 'error' | undefined | Validation status. |
to | string | HTMLElement | false | body | Container node of the menu. |
virtual-scroll | boolean | true | Whether to enable virtual scrolling. |
CascaderOption Properties
| Name | Type | Description |
|---|
label | string | Label of the option. |
value | string | number | Value of the option. |
disabled? | boolean | Whether this option is disabled. |
children? | CascaderOption[] | The children options. |
Events
| Name | Parameters | Description |
|---|
update:value | (value, option, pathValues) | Triggered when value changes. |
update:show | (value: boolean) | Triggered when menu opens/closes. |
blur | () | Triggered on blur. |
focus | () | Triggered on focus. |
load | (option: CascaderOption) => Promise<void> | Callback when a node is loaded (for remote). |
Slots
| Name | Parameters | Description |
|---|
action | () | Action content in the cascading menu. |
arrow | () | Arrow content in the cascading menu. |
empty | () | Empty state slot for options. |
not-found | () | Data not found slot when searching. |
Methods
| Name | Type | Description |
|---|
blur | () => void | Blur the cascader. |
focus | () => void | Focus the cascader. |
getCheckedData | () => { keys, options } | Get checked data. |
getIndeterminateData | () => { keys, options } | Get indeterminate data. |
Common Patterns
Async Loading
<template>
<n-cascader
v-model:value="value"
placeholder="Select option"
:options="options"
remote
:on-load="handleLoad"
/>
</template>
<script setup>
import { ref } from 'vue';
const value = ref(null);
const options = ref([
{
label: 'Root',
value: 'root',
},
]);
const handleLoad = async option => {
const children = await fetchChildren(option.value);
option.children = children;
};
</script>
Check Strategies
<template>
<n-space vertical>
<n-radio-group v-model:value="checkStrategy">
<n-radio-button value="all">All</n-radio-button>
<n-radio-button value="parent">Parent</n-radio-button>
<n-radio-button value="child">Child</n-radio-button>
</n-radio-group>
<n-cascader
multiple
cascade
:check-strategy="checkStrategy"
:options="options"
/>
</n-space>
</template>
<script setup>
import { ref } from 'vue';
const checkStrategy = ref('all');
</script>
Custom Field Names
<template>
<n-cascader
:options="options"
label-field="name"
value-field="id"
children-field="items"
/>
</template>
<script setup>
const options = [
{
name: 'Category',
id: 'cat1',
items: [{ name: 'Sub Category', id: 'sub1' }],
},
];
</script>
Filterable with Hover Trigger
<template>
<n-cascader
v-model:value="value"
placeholder="Select option"
:options="options"
:expand-trigger="'hover'"
:filterable="true"
/>
</template>
Custom Label Rendering
<template>
<n-cascader
v-model:value="value"
:options="options"
:render-label="renderLabel"
/>
</template>
<script setup>
import { h } from 'vue';
const renderLabel = option => {
return h('span', { style: { fontWeight: 'bold' } }, option.label);
};
</script>
Large Data Handling
<template>
<n-cascader
v-model:value="value"
placeholder="Select from large dataset"
:options="options"
:virtual-scroll="true"
:filterable="true"
/>
</template>
Using Methods via Ref
<template>
<n-space item-style="display: flex; align-item: center;">
<n-button @click="handleClick">Focus then blur in 1 second</n-button>
<n-cascader ref="cascaderRef" style="width: 200px" />
</n-space>
</template>
<script setup>
import { ref } from 'vue';
const cascaderRef = ref(null);
const handleClick = () => {
cascaderRef.value?.focus();
setTimeout(() => {
cascaderRef.value?.blur();
}, 1000);
};
</script>
Best Practices
-
Choose appropriate check-strategy: Use 'child' when you only want leaf nodes selected, 'parent' for cleaner display when all children are selected, and 'all' for full flexibility.
-
Use cascade wisely: Enable cascade when parent-child selection should be linked. Disable it for independent selection behavior.
-
Implement async loading for large datasets: Use remote and on-load for lazy loading to improve initial render performance.
-
Enable virtual-scroll for large data: Keep virtual-scroll: true (default) for smooth scrolling with thousands of options.
-
Customize field names for backend data: Use label-field, value-field, and children-field to match your API response structure without data transformation.
-
Use show-path for clarity: Keep show-path: true to show the full selection path, helping users understand their selection context.
-
Handle disabled nodes carefully: When using allow-checking-not-loaded, be aware of consistency between frontend and backend checking logic.
-
Use max-tag-count: 'responsive': For multiple selection with many items, this keeps the display clean and responsive.