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
cascadewisely: Enablecascadewhen parent-child selection should be linked. Disable it for independent selection behavior.Implement async loading for large datasets: Use
remoteandon-loadfor 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, andchildren-fieldto match your API response structure without data transformation.Use
show-pathfor clarity: Keepshow-path: trueto 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.