Cascader
Overview
A cascader for selecting values from hierarchical tree data. It renders a linked multi-column panel and supports single/multiple selection, full-path value mode, parent-child check-state propagation, local filtering and remote search, lazy loading of children, and virtual scrolling for large datasets. Use it when options are organized as a tree and selection must happen level by level; for flat option lists, prefer SSelect or SCombobox.
Usage
Features
- 🗂 Linked multi-column panel — the path unfolds one level per column
- ☑️ Single or multiple selection with cascading parent-child check states (
showCheckedStrategy: child / parent) - 🛤 Full-path value mode (
pathMode) — the model value carries the complete value/label path - ⏳ Data loading — lazy children (
loadChildren), debounced remote search (searchDelay), local filtering (filter) with a localized empty state - 📜 Built-in per-column virtual scrolling (
virtualScroll, configurableitemSize/height) - ⌨️ Full keyboard navigation — Arrow keys move across columns, Enter selects, plus click/hover expand
- ♿ WAI-ARIA tree semantics — trigger
role="combobox"+aria-haspopup="tree", optionrole="treeitem", axe-clean when open - 🎨 16 recipe slots and 7 size variants via
cascaderVariants
Demos
Basic
Selected: "None"
Multiple
Searchable
Selected: None
LazyLoad
Selected: None
RemoteSearch
Selected: None
VirtualScroll
Selected: None
CustomOption
API
Aria Layer
17Cascader<T, M, P>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
class | ClassValue | — | the class of cascader trigger |
ui | Partial<CascaderUi> | — | Per-slot class overrides for the component. |
size | ThemeSize | — | Visual size of the component. |
showArrow | boolean | true | When `true`, the arrow icon is rendered. |
placement | import("@/index").Placement | — | The placement of the content. |
triggerProps | CascaderTriggerProps | — | Properties forwarded to the trigger part. |
valueProps | CascaderValueProps | — | Properties forwarded to the value part. |
searchInputProps | CascaderSearchInputProps | — | Properties forwarded to the search input part. |
portalProps | PortalProps | — | Properties forwarded to the portal part. |
contentProps | CascaderContentProps | — | Properties forwarded to the content part. |
menuProps | CascaderMenuProps | — | Properties forwarded to every menu part. |
optionProps | Partial<CascaderOptionProps<T>> | — | Properties forwarded to every option part. |
emptyProps | CascaderEmptyProps | — | Properties forwarded to the empty part. |
emptyLabel | string | The locale message | The text shown in the empty state. |
clearLabel | string | The locale message | The accessible label of the clear button. |
arrowProps | PopperArrowProps | — | Properties forwarded to the arrow part. |
modelValue | CascaderValueType<T, M, P> | — | The controlled value of the selected node(s). Can be bound with `v-model`. |
defaultValue | CascaderValueType<T, M, P> | — | The default value of the selected node(s). |
multiple | M | — | When `true`, multiple nodes can be selected. |
pathMode | P | false | When `true`, the model value is the full path array(s) instead of the node value(s). |
options | CascaderOptionData<T>[] | — | Options of the cascader. |
fieldKeys | CascaderFieldKeys | — | Field keys used to extract the option fields. |
open | boolean | — | The controlled open state of the Cascader. Can be bound as `v-model:open`. |
defaultOpen | boolean | — | The open state of the cascader when it is initially rendered. |
disabled | boolean | — | When `true`, prevents the user from interacting with the Cascader. |
clearable | boolean | — | When `true`, the value can be cleared by the clear button. |
expandTrigger | 'click' | 'hover' | 'click' | The trigger to expand the children of a node. |
checkStrictly | boolean | false | When `false`, only leaf nodes can be selected (single) or the parent-children check states
are linked (multiple). When `true`, any node can be selected independently. |
showCheckedStrategy | 'child' | 'parent' | 'child' | The strategy used to collect and display checked nodes in multiple mode.
- `child`: collect the leaves of the checked region.
- `parent`: collect the topmost checked nodes (fold fully-checked subtrees into parents). |
separator | string | ' / ' | The separator used to join the path labels. |
filterable | boolean | — | When `true`, the trigger becomes a search input and the panel shows flat filtered results. |
filter | ((pattern: string, option: CascaderOptionData<T>, path: string[]) => boolean) | — | Custom filter function used in local filtering mode. The default performs a
case-insensitive `includes` match against every label of the path. |
remote | boolean | — | When `true`, the panel loads its options from `onSearch` instead of filtering locally. |
onSearch | ((pattern: string) => Promise<CascaderOptionData<T>[]>) | — | Async search function used in remote mode. Returns the flat options for the keyword. |
searchDelay | number | 300 | Debounce delay in milliseconds for filtering and remote search. |
lazy | boolean | — | When `true`, children of a node are loaded asynchronously via `onLoad`. |
onLoad | ((option: CascaderNode<T>) => Promise<CascaderOptionData<T>[]>) | — | Async function used to load the children of a node when `lazy` is `true`. |
virtualScroll | boolean | — | When `true`, only the visible rows of each column are rendered. |
itemSize | number | 34 | The fixed height of a row used by virtual scrolling. |
height | number | 204 | The height of the panel used by virtual scrolling. |
dir | Direction | — | The reading direction of the component. |
placeholder | string | — | The content shown when no node is selected. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | CascaderValueType<T, M, P> | Event handler called when the value of the cascader changes. Can be bound as `v-model`. |
update:open | boolean | Event handler called when the open state of the cascader changes. Can be bound as `v-model:open`. |
change | CascaderValueType<T, M, P> | undefined, nodes: CascaderNode<T>[] | Event handler called when the value changes, with the selected nodes. |
clear | — | Event handler called when the selection is cleared. |
loaded | CascaderNode<T> | Event handler called when the children of a node have been loaded (lazy mode). |
closeAutoFocus | Event | Emitted when close auto focus occurs. |
escapeKeyDown | KeyboardEvent | Event handler called when the escape key is down. Can be prevented. |
pointerDownOutside | PointerDownOutsideEvent | Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
placed | — | Emitted when the content is placed. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
trigger-icon | — | Custom content for the trigger icon (arrow). |
trigger-value | CascaderCompactTriggerValueSlotProps<T, M, P> | Custom content for the trigger value. |
search-input | — | Custom content for the search input. |
option | CascaderCompactOptionSlotProps<T> | Custom content for a single option. |
tag | CascaderCompactTagSlotProps<T> | Custom content for a tag in multiple mode. |
empty | — | Custom content for the empty state. |
CascaderArrow
CascaderClear
Props
| Prop | Type | Default | Description |
|---|---|---|---|
ariaLabel | string | '清除' | The accessible label of the clear button. |
CascaderCompact<T, M, P>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
showArrow | boolean | true | When `true`, the arrow icon is rendered. |
placement | import("@/index").Placement | — | The placement of the content. |
triggerProps | CascaderTriggerProps | — | Properties forwarded to the trigger part. |
valueProps | CascaderValueProps | — | Properties forwarded to the value part. |
searchInputProps | CascaderSearchInputProps | — | Properties forwarded to the search input part. |
portalProps | PortalProps | — | Properties forwarded to the portal part. |
contentProps | CascaderContentProps | — | Properties forwarded to the content part. |
menuProps | CascaderMenuProps | — | Properties forwarded to every menu part. |
optionProps | Partial<CascaderOptionProps<T>> | — | Properties forwarded to every option part. |
emptyProps | CascaderEmptyProps | — | Properties forwarded to the empty part. |
emptyLabel | string | The locale message | The text shown in the empty state. |
clearLabel | string | The locale message | The accessible label of the clear button. |
arrowProps | PopperArrowProps | — | Properties forwarded to the arrow part. |
modelValue | CascaderValueType<T, M, P> | — | The controlled value of the selected node(s). Can be bound with `v-model`. |
defaultValue | CascaderValueType<T, M, P> | — | The default value of the selected node(s). |
multiple | M | — | When `true`, multiple nodes can be selected. |
pathMode | P | false | When `true`, the model value is the full path array(s) instead of the node value(s). |
options | CascaderOptionData<T>[] | — | Options of the cascader. |
fieldKeys | CascaderFieldKeys | — | Field keys used to extract the option fields. |
open | boolean | — | The controlled open state of the Cascader. Can be bound as `v-model:open`. |
defaultOpen | boolean | — | The open state of the cascader when it is initially rendered. |
disabled | boolean | — | When `true`, prevents the user from interacting with the Cascader. |
clearable | boolean | — | When `true`, the value can be cleared by the clear button. |
expandTrigger | 'click' | 'hover' | 'click' | The trigger to expand the children of a node. |
checkStrictly | boolean | false | When `false`, only leaf nodes can be selected (single) or the parent-children check states
are linked (multiple). When `true`, any node can be selected independently. |
showCheckedStrategy | 'child' | 'parent' | 'child' | The strategy used to collect and display checked nodes in multiple mode.
- `child`: collect the leaves of the checked region.
- `parent`: collect the topmost checked nodes (fold fully-checked subtrees into parents). |
separator | string | ' / ' | The separator used to join the path labels. |
filterable | boolean | — | When `true`, the trigger becomes a search input and the panel shows flat filtered results. |
filter | ((pattern: string, option: CascaderOptionData<T>, path: string[]) => boolean) | — | Custom filter function used in local filtering mode. The default performs a
case-insensitive `includes` match against every label of the path. |
remote | boolean | — | When `true`, the panel loads its options from `onSearch` instead of filtering locally. |
onSearch | ((pattern: string) => Promise<CascaderOptionData<T>[]>) | — | Async search function used in remote mode. Returns the flat options for the keyword. |
searchDelay | number | 300 | Debounce delay in milliseconds for filtering and remote search. |
lazy | boolean | — | When `true`, children of a node are loaded asynchronously via `onLoad`. |
onLoad | ((option: CascaderNode<T>) => Promise<CascaderOptionData<T>[]>) | — | Async function used to load the children of a node when `lazy` is `true`. |
virtualScroll | boolean | — | When `true`, only the visible rows of each column are rendered. |
itemSize | number | 34 | The fixed height of a row used by virtual scrolling. |
height | number | 204 | The height of the panel used by virtual scrolling. |
dir | Direction | — | The reading direction of the component. |
placeholder | string | — | The content shown when no node is selected. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | CascaderValueType<T, M, P> | Event handler called when the value of the cascader changes. Can be bound as `v-model`. |
update:open | boolean | Event handler called when the open state of the cascader changes. Can be bound as `v-model:open`. |
change | CascaderValueType<T, M, P> | undefined, nodes: CascaderNode<T>[] | Event handler called when the value changes, with the selected nodes. |
clear | — | Event handler called when the selection is cleared. |
loaded | CascaderNode<T> | Event handler called when the children of a node have been loaded (lazy mode). |
closeAutoFocus | Event | Emitted when close auto focus occurs. |
escapeKeyDown | KeyboardEvent | Event handler called when the escape key is down. Can be prevented. |
pointerDownOutside | PointerDownOutsideEvent | Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
placed | — | Emitted when the content is placed. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
trigger-icon | — | Custom content for the trigger icon (arrow). |
trigger-value | CascaderCompactTriggerValueSlotProps<T, M, P> | Custom content for the trigger value. |
search-input | — | Custom content for the search input. |
option | CascaderCompactOptionSlotProps<T> | Custom content for a single option. |
tag | CascaderCompactTagSlotProps<T> | Custom content for a tag in multiple mode. |
empty | — | Custom content for the empty state. |
CascaderCompactOption
CascaderCompactTag
CascaderCompactTriggerValue
CascaderContent
Props
| Prop | Type | Default | Description |
|---|---|---|---|
menuProps | CascaderMenuProps | — | Properties forwarded to every menu part. |
emptyProps | CascaderEmptyProps | — | Properties forwarded to the empty part. |
open | boolean | true | Whether the floating layer is open. Drives the positioning lifecycle (`isPositioned`
resets when open flips); the positioning primitive itself has no open state, so
consumers wire their own open state here. |
placement | Placement | undefined | The placement of the floating element.
If used, it will override the `side` and `align` props. |
side | Side | 'bottom' | The preferred side of the anchor to render against when open. Will be reversed when collisions occur and
avoidCollisions is enabled. |
sideOffset | number | 0 | The distance in pixels from the anchor. |
sideFlip | boolean | true | Flip to the opposite side when colliding with boundary. |
align | Align | 'center' | The preferred alignment against the anchor. May change when collisions occur. |
alignOffset | number | 0 | An offset in pixels from the `start` or `end` alignment options. |
alignFlip | boolean | true | Flip alignment when colliding with boundary.
May only occur when `prioritizePosition` is true. |
avoidCollisions | boolean | true | When `true`, overrides the side and align preferences to prevent collisions with boundary edges. |
collisionBoundary | Element | (Element | null)[] | null | [ ] | The element used as the collision boundary. By default this is the viewport, though you can provide additional
element(s) to be included in this check. |
collisionPadding | Padding | 0 | The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for
all sides), or a partial padding object, for example: { top: 20, left: 20 }. |
arrowPadding | number | 0 | The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it
from overflowing the corners. |
hideShiftedArrow | boolean | false | When `true`, hides the arrow when it cannot be centered
to the reference element. |
sticky | 'partial' | 'always' | 'partial' | The sticky behavior on the align axis. `partial` will keep the content in the boundary as long as the anchor is at
least partially in the boundary whilst "always" will keep the content in the boundary regardless. |
hideWhenDetached | boolean | false | Whether to hide the content when the anchor becomes fully occluded. |
positionStrategy | 'fixed' | 'absolute' | 'fixed' | The type of CSS position property to use. |
updatePositionStrategy | 'always' | 'optimized' | 'optimized' | Strategy to update the position of the floating element on every animation frame. |
disableUpdateOnLayoutShift | boolean | false | Whether to disable the update position for the content when the layout shifted. |
prioritizePosition | boolean | false | Force content to be position within the viewport. Might overlap the reference element, which may not be desired. |
reference | ReferenceElement | — | The custom element or virtual element that will be set as the reference to position the floating element. If
provided, it will replace the default anchor element. |
disableOutsidePointerEvents | boolean | — | When `true`, hover/focus/click interactions will be disabled on elements outside the `DismissableLayer`. Users will
need to click twice on outside elements to interact with them: once to close the `DismissableLayer`, and again to
trigger the element. |
forceMount | boolean | — | Used to force mounting when more control is needed.
Useful when controlling animation with Vue animation libraries. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
closeAutoFocus | Event | Emitted when close auto focus occurs. |
escapeKeyDown | KeyboardEvent | Event handler called when the escape key is down. Can be prevented. |
pointerDownOutside | PointerDownOutsideEvent | Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
placed | — | Emitted when the content is placed. |
CascaderEmpty
CascaderMenu
Props
| Prop | Type | Default | Description |
|---|---|---|---|
level | number | — | The depth of the menu column. |
optionProps | Partial<CascaderOptionProps<DefinedValue>> | — | Properties forwarded to every option part. |
CascaderOption<T>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
node | CascaderNode<T extends DefinedValue = DefinedValue> | — | The node rendered by the option. |
index | number | — | The position of the node inside its column. |
level | number | — | The depth of the column the option belongs to. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
select | CascaderSelectEvent<T> | Event handler called when the node is selected. Can be prevented by calling `event.preventDefault`. |
expand | CascaderExpandEvent<T> | Event handler called when the node is expanded. Can be prevented by calling `event.preventDefault`. |
CascaderPortal
Props
| Prop | Type | Default | Description |
|---|---|---|---|
to | string | HTMLElement | — | Vue native teleport component prop `:to`
{@link https://vuejs.org/guide/built-ins/teleport.html#basic-usage} |
disabled | boolean | — | Disable teleport and render the component inline
{@link https://vuejs.org/guide/built-ins/teleport.html#disabling-teleport} |
defer | boolean | — | Defer the resolving of a Teleport target until other parts of the application have mounted (requires Vue 3.5.0+)
{@link https://vuejs.org/guide/built-ins/teleport.html#deferred-teleport} |
forceMount | boolean | — | Used to force mounting when more control is needed.
Useful when controlling animation with Vue animation libraries. |
CascaderRoot<T, M, P>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | CascaderValueType<T, M, P> | — | The controlled value of the selected node(s). Can be bound with `v-model`. |
defaultValue | CascaderValueType<T, M, P> | — | The default value of the selected node(s). |
multiple | M | — | When `true`, multiple nodes can be selected. |
pathMode | P | false | When `true`, the model value is the full path array(s) instead of the node value(s). |
options | CascaderOptionData<T>[] | — | Options of the cascader. |
fieldKeys | CascaderFieldKeys | — | Field keys used to extract the option fields. |
open | boolean | — | The controlled open state of the Cascader. Can be bound as `v-model:open`. |
defaultOpen | boolean | — | The open state of the cascader when it is initially rendered. |
disabled | boolean | — | When `true`, prevents the user from interacting with the Cascader. |
clearable | boolean | — | When `true`, the value can be cleared by the clear button. |
expandTrigger | 'click' | 'hover' | 'click' | The trigger to expand the children of a node. |
checkStrictly | boolean | false | When `false`, only leaf nodes can be selected (single) or the parent-children check states
are linked (multiple). When `true`, any node can be selected independently. |
showCheckedStrategy | 'child' | 'parent' | 'child' | The strategy used to collect and display checked nodes in multiple mode.
- `child`: collect the leaves of the checked region.
- `parent`: collect the topmost checked nodes (fold fully-checked subtrees into parents). |
separator | string | ' / ' | The separator used to join the path labels. |
filterable | boolean | — | When `true`, the trigger becomes a search input and the panel shows flat filtered results. |
filter | ((pattern: string, option: CascaderOptionData<T>, path: string[]) => boolean) | — | Custom filter function used in local filtering mode. The default performs a
case-insensitive `includes` match against every label of the path. |
remote | boolean | — | When `true`, the panel loads its options from `onSearch` instead of filtering locally. |
onSearch | ((pattern: string) => Promise<CascaderOptionData<T>[]>) | — | Async search function used in remote mode. Returns the flat options for the keyword. |
searchDelay | number | 300 | Debounce delay in milliseconds for filtering and remote search. |
lazy | boolean | — | When `true`, children of a node are loaded asynchronously via `onLoad`. |
onLoad | ((option: CascaderNode<T>) => Promise<CascaderOptionData<T>[]>) | — | Async function used to load the children of a node when `lazy` is `true`. |
virtualScroll | boolean | — | When `true`, only the visible rows of each column are rendered. |
itemSize | number | 34 | The fixed height of a row used by virtual scrolling. |
height | number | 204 | The height of the panel used by virtual scrolling. |
dir | Direction | — | The reading direction of the component. |
placeholder | string | — | The content shown when no node is selected. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | CascaderValueType<T, M, P> | Event handler called when the value of the cascader changes. Can be bound as `v-model`. |
update:open | boolean | Event handler called when the open state of the cascader changes. Can be bound as `v-model:open`. |
change | CascaderValueType<T, M, P> | undefined, nodes: CascaderNode<T>[] | Event handler called when the value changes, with the selected nodes. |
clear | — | Event handler called when the selection is cleared. |
loaded | CascaderNode<T> | Event handler called when the children of a node have been loaded (lazy mode). |
CascaderSearchInput
CascaderTags
Slots
| Slot Name | Parameters | Description |
|---|---|---|
tag | CascaderCompactTagSlotProps<T> | Custom content for a single tag in multiple mode. |
value | — | Custom content shown when there is no selection. |
CascaderTrigger
Props
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | — | When `true`, prevents the user from interacting with the trigger. |
reference | ReferenceElement | — | — |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
CascaderValue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | — | The content shown when no node is selected. |
Notes
Architecture and benchmark differences
VeanUI implements cascader with a self-developed data engine (useCascaderData) rather than reusing the listbox selection/collection bases, whose flat single-value model does not fit tree cascading: shallowReactive node trees cache pathValues / pathLabels / level for O(1) lookups, the menus computed derives the visible columns, and cascading checks run setCheckedDeep / recomputeAncestors / collectCheckedNodes. CascaderOption dispatches cancellable select / expand custom events (reka-ui style). The scv() recipe cascaderVariants declares 16 slots and 7 size variants.
| Capability | VeanUI | Ant Design Cascader | reka-ui Cascader | Element Plus Cascader |
|---|---|---|---|---|
| Aria/styled split | ✅ | — | ✅ | — |
| Multi-column panel | ✅ | ✅ | ✅ | ✅ |
| Cascading checks + half-check | ✅ | ✅ | — | ✅ |
| Lazy loading / remote search | ✅ | ✅ | ✅ | ✅ |
showCheckedStrategy | ✅ | ✅ | — | — |
pathMode (path values) | ✅ | ✅ | — | — |
| Virtual scrolling | ✅ | — | — | — |
| Cancellable custom events | ✅ | — | ✅ | — |
| Localized strings (not hardcoded) | ✅ | — | — | ✅ |
| axe-clean (open state) | ✅ | — | — | — |
Cautions
- All built-in strings are localized (
LocaleCascaderMessages); override per instance withemptyLabel/clearLabelor the matchingaria-labelattrs. - In filterable mode the trigger becomes
tabindex=-1and focus lives in the search input — keyboard navigation starts there. - Clicking a non-leaf node in search mode only highlights it; the multi-column path does not expand (differs from AntD) — expand on demand if you need that behavior.
select/expandevents still fire on disabled items (emitted before the guard) without changing the model value; guard in the consumer if needed.
FAQ
How do I get the full path instead of the last value?
Enable pathMode; the model value then carries the complete value/label path rather than the deepest node only.
How do I load children lazily from an API?
Pass loadChildren returning the children for a node; the engine tracks the loading state and emits loaded when it finishes.
How do I filter remotely?
Use searchDelay for debouncing and provide your own filter implementation (or feed filtered items); the built-in filtering matches path labels client-side.
How do I emit only checked leaves?
Configure showCheckedStrategy: 'child' to collect only leaf nodes when a parent is checked, or 'parent' to emit the checked parents.