# Cascade Select URL: https://ark-ui.com/docs/components/cascade-select Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/cascade-select.mdx Displays nested options in cascading dropdown panels. --- ## Anatomy ```tsx ``` ## Examples **Example: basic** #### React ```tsx import { Portal } from '@ark-ui/react/portal' import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/react/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react' import styles from 'styles/cascade-select.module.css' export const Basic = () => ( Location ) const TreeNode = ({ node, indexPath = [], value = [] }: { node: Node; indexPath?: number[]; value?: string[] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, { label: 'Canada', value: 'canada', children: [ { label: 'Ontario', value: 'ontario' }, { label: 'Quebec', value: 'quebec' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, { label: 'Germany', value: 'germany', children: [ { label: 'Berlin', value: 'berlin' }, { label: 'Munich', value: 'munich' }, ], }, ], }, ], }, }) ``` #### Solid ```tsx import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/solid/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-solid' import { For, Show } from 'solid-js' import { Portal } from 'solid-js/web' import styles from 'styles/cascade-select.module.css' export const Basic = () => ( Location ) const TreeNode = (props: { node: Node; indexPath?: number[]; value?: string[] }) => { const context = useCascadeSelectContext() const nodeState = () => context().getItemState({ item: props.node, indexPath: props.indexPath ?? [], value: props.value ?? [] }) return ( <> {(child, getIndex) => ( {collection.stringifyNode(child)} ✓} > )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, { label: 'Canada', value: 'canada', children: [ { label: 'Ontario', value: 'ontario' }, { label: 'Quebec', value: 'quebec' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, { label: 'Germany', value: 'germany', children: [ { label: 'Berlin', value: 'berlin' }, { label: 'Munich', value: 'munich' }, ], }, ], }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Location {#snippet render(api)} {@render renderNode(api, collection.rootNode, [], [])} {/snippet} {#snippet renderNode(api: UseCascadeSelectReturn, node: Node, indexPath: number[], value: string[])} {@const nodeState = api().getItemState({ item: node, indexPath, value })} {#each collection.getNodeChildren(node) as child, i} {collection.stringifyNode(child)} {#if collection.isBranchNode(child)} {:else} {/if} {/each} {#if nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild)} {@render renderNode( api, nodeState.highlightedChild as Node, [...indexPath, nodeState.highlightedIndex], [...value, collection.getNodeValue(nodeState.highlightedChild as Node)], )} {/if} {/snippet} ``` ### Controlled Use the `value` and `onValueChange` props to control the selected value. **Example: controlled** #### React ```tsx import { Portal } from '@ark-ui/react/portal' import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/react/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react' import { useState } from 'react' import styles from 'styles/cascade-select.module.css' export const Controlled = () => { const [value, setValue] = useState([]) return ( setValue(details.value)} > Location ) } const TreeNode = ({ node, indexPath = [], value = [] }: { node: Node; indexPath?: number[]; value?: string[] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, { label: 'Canada', value: 'canada', children: [ { label: 'Ontario', value: 'ontario' }, { label: 'Quebec', value: 'quebec' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Solid ```tsx import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/solid/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-solid' import { For, Show, createSignal } from 'solid-js' import { Portal } from 'solid-js/web' import styles from 'styles/cascade-select.module.css' export const Controlled = () => { const [value, setValue] = createSignal([]) return ( setValue(details.value)} > Location ) } const TreeNode = (props: { node: Node; indexPath?: number[]; value?: string[] }) => { const context = useCascadeSelectContext() const nodeState = () => context().getItemState({ item: props.node, indexPath: props.indexPath ?? [], value: props.value ?? [] }) return ( <> {(child, getIndex) => ( {collection.stringifyNode(child)} ✓} > )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, { label: 'Canada', value: 'canada', children: [ { label: 'Ontario', value: 'ontario' }, { label: 'Quebec', value: 'quebec' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte { value = details.value }} > Location {#snippet render(api)} {@render renderNode(api, collection.rootNode, [], [])} {/snippet} {#snippet renderNode(api: UseCascadeSelectReturn, node: Node, indexPath: number[], nodeValue: string[])} {@const nodeState = api().getItemState({ item: node, indexPath, value: nodeValue })} {#each collection.getNodeChildren(node) as child, i} {collection.stringifyNode(child)} {#if collection.isBranchNode(child)} {:else} {/if} {/each} {#if nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild)} {@render renderNode( api, nodeState.highlightedChild as Node, [...indexPath, nodeState.highlightedIndex], [...nodeValue, collection.getNodeValue(nodeState.highlightedChild as Node)], )} {/if} {/snippet} ``` ### Root Provider An alternative way to control the cascade select is to use the `RootProvider` component and the `useCascadeSelect` hook. This gives you access to state and methods from outside the component. **Example: root-provider** #### React ```tsx import { Portal } from '@ark-ui/react/portal' import { CascadeSelect, createCascadeCollection, useCascadeSelect, useCascadeSelectContext, } from '@ark-ui/react/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react' import styles from 'styles/cascade-select.module.css' export const RootProvider = () => { const api = useCascadeSelect({ collection }) return ( <> value: {JSON.stringify(api.value)} Location ) } const TreeNode = ({ node, indexPath = [], value = [] }: { node: Node; indexPath?: number[]; value?: string[] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Solid ```tsx import { CascadeSelect, createCascadeCollection, useCascadeSelect, useCascadeSelectContext, } from '@ark-ui/solid/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-solid' import { For, Show } from 'solid-js' import { Portal } from 'solid-js/web' import styles from 'styles/cascade-select.module.css' export const RootProvider = () => { const api = useCascadeSelect({ collection }) return ( <> value: {JSON.stringify(api().value)} Location ) } const TreeNode = (props: { node: Node; indexPath?: number[]; value?: string[] }) => { const context = useCascadeSelectContext() const nodeState = () => context().getItemState({ item: props.node, indexPath: props.indexPath ?? [], value: props.value ?? [] }) return ( <> {(child, getIndex) => ( {collection.stringifyNode(child)} ✓} > )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte value: {JSON.stringify(cascadeSelect().value)} Location {@render renderNode(cascadeSelect, collection.rootNode, [], [])} {#snippet renderNode(api: UseCascadeSelectReturn, node: Node, indexPath: number[], value: string[])} {@const nodeState = api().getItemState({ item: node, indexPath, value })} {#each collection.getNodeChildren(node) as child, i} {collection.stringifyNode(child)} {#if collection.isBranchNode(child)} {:else} {/if} {/each} {#if nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild)} {@render renderNode( api, nodeState.highlightedChild as Node, [...indexPath, nodeState.highlightedIndex], [...value, collection.getNodeValue(nodeState.highlightedChild as Node)], )} {/if} {/snippet} ``` ### Multiple Enable multiple selection with the `multiple` prop. Users can select more than one leaf value. **Example: multiple** #### React ```tsx import { Portal } from '@ark-ui/react/portal' import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/react/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react' import styles from 'styles/cascade-select.module.css' export const Multiple = () => ( Locations ) const TreeNode = ({ node, indexPath = [], value = [] }: { node: Node; indexPath?: number[]; value?: string[] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, { label: 'Canada', value: 'canada', children: [ { label: 'Ontario', value: 'ontario' }, { label: 'Quebec', value: 'quebec' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, { label: 'Germany', value: 'germany', children: [ { label: 'Berlin', value: 'berlin' }, { label: 'Munich', value: 'munich' }, ], }, ], }, ], }, }) ``` #### Solid ```tsx import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/solid/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-solid' import { For, Show } from 'solid-js' import { Portal } from 'solid-js/web' import styles from 'styles/cascade-select.module.css' export const Multiple = () => ( Locations ) const TreeNode = (props: { node: Node; indexPath?: number[]; value?: string[] }) => { const context = useCascadeSelectContext() const nodeState = () => context().getItemState({ item: props.node, indexPath: props.indexPath ?? [], value: props.value ?? [] }) return ( <> {(child, getIndex) => ( {collection.stringifyNode(child)} ✓} > )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, { label: 'Canada', value: 'canada', children: [ { label: 'Ontario', value: 'ontario' }, { label: 'Quebec', value: 'quebec' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Locations {#snippet render(api)} {@render renderNode(api, collection.rootNode, [], [])} {/snippet} {#snippet renderNode(api: UseCascadeSelectReturn, node: Node, indexPath: number[], value: string[])} {@const nodeState = api().getItemState({ item: node, indexPath, value })} {#each collection.getNodeChildren(node) as child, i} {collection.stringifyNode(child)} {#if collection.isBranchNode(child)} {:else} {/if} {/each} {#if nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild)} {@render renderNode( api, nodeState.highlightedChild as Node, [...indexPath, nodeState.highlightedIndex], [...value, collection.getNodeValue(nodeState.highlightedChild as Node)], )} {/if} {/snippet} ``` ### Hover Trigger Use `highlightTrigger="hover"` to highlight items on hover instead of requiring keyboard navigation or click. **Example: hover-trigger** #### React ```tsx import { Portal } from '@ark-ui/react/portal' import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/react/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react' import styles from 'styles/cascade-select.module.css' export const HoverTrigger = () => ( Location ) const TreeNode = ({ node, indexPath = [], value = [] }: { node: Node; indexPath?: number[]; value?: string[] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, { label: 'Canada', value: 'canada', children: [ { label: 'Ontario', value: 'ontario' }, { label: 'Quebec', value: 'quebec' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, { label: 'Germany', value: 'germany', children: [ { label: 'Berlin', value: 'berlin' }, { label: 'Munich', value: 'munich' }, ], }, ], }, ], }, }) ``` #### Solid ```tsx import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/solid/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-solid' import { For, Show } from 'solid-js' import { Portal } from 'solid-js/web' import styles from 'styles/cascade-select.module.css' export const HoverTrigger = () => ( Location ) const TreeNode = (props: { node: Node; indexPath?: number[]; value?: string[] }) => { const context = useCascadeSelectContext() const nodeState = () => context().getItemState({ item: props.node, indexPath: props.indexPath ?? [], value: props.value ?? [] }) return ( <> {(child, getIndex) => ( {collection.stringifyNode(child)} ✓} > )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Location {#snippet render(api)} {@render renderNode(api, collection.rootNode, [], [])} {/snippet} {#snippet renderNode(api: UseCascadeSelectReturn, node: Node, indexPath: number[], value: string[])} {@const nodeState = api().getItemState({ item: node, indexPath, value })} {#each collection.getNodeChildren(node) as child, i} {collection.stringifyNode(child)} {#if collection.isBranchNode(child)} {:else} {/if} {/each} {#if nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild)} {@render renderNode( api, nodeState.highlightedChild as Node, [...indexPath, nodeState.highlightedIndex], [...value, collection.getNodeValue(nodeState.highlightedChild as Node)], )} {/if} {/snippet} ``` ### Allow Parent Selection By default, only leaf nodes can be selected. Use `allowParentSelection` to allow branch nodes to be selected as well. **Example: allow-parent-selection** #### React ```tsx import { Portal } from '@ark-ui/react/portal' import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/react/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react' import styles from 'styles/cascade-select.module.css' export const AllowParentSelection = () => ( Category ) const TreeNode = ({ node, indexPath = [], value = [] }: { node: Node; indexPath?: number[]; value?: string[] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Electronics', value: 'electronics', children: [ { label: 'Phones', value: 'phones', children: [ { label: 'Android', value: 'android' }, { label: 'iPhone', value: 'iphone' }, ], }, { label: 'Laptops', value: 'laptops', children: [ { label: 'Gaming', value: 'gaming-laptop' }, { label: 'Ultrabook', value: 'ultrabook' }, ], }, ], }, { label: 'Clothing', value: 'clothing', children: [ { label: 'Shirts', value: 'shirts' }, { label: 'Pants', value: 'pants' }, ], }, ], }, }) ``` #### Solid ```tsx import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/solid/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-solid' import { For, Show } from 'solid-js' import { Portal } from 'solid-js/web' import styles from 'styles/cascade-select.module.css' export const AllowParentSelection = () => ( Category ) const TreeNode = (props: { node: Node; indexPath?: number[]; value?: string[] }) => { const context = useCascadeSelectContext() const nodeState = () => context().getItemState({ item: props.node, indexPath: props.indexPath ?? [], value: props.value ?? [] }) return ( <> {(child, getIndex) => ( {collection.stringifyNode(child)} ✓} > )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Electronics', value: 'electronics', children: [ { label: 'Phones', value: 'phones', children: [ { label: 'Android', value: 'android' }, { label: 'iPhone', value: 'iphone' }, ], }, { label: 'Laptops', value: 'laptops', children: [ { label: 'Gaming', value: 'gaming-laptop' }, { label: 'Ultrabook', value: 'ultrabook' }, ], }, ], }, { label: 'Clothing', value: 'clothing', children: [ { label: 'Shirts', value: 'shirts' }, { label: 'Pants', value: 'pants' }, ], }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Category {#snippet render(api)} {@render renderNode(api, collection.rootNode, [], [])} {/snippet} {#snippet renderNode(api: UseCascadeSelectReturn, node: Node, indexPath: number[], value: string[])} {@const nodeState = api().getItemState({ item: node, indexPath, value })} {#each collection.getNodeChildren(node) as child, i} {collection.stringifyNode(child)} {#if collection.isBranchNode(child)} {:else} {/if} {/each} {#if nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild)} {@render renderNode( api, nodeState.highlightedChild as Node, [...indexPath, nodeState.highlightedIndex], [...value, collection.getNodeValue(nodeState.highlightedChild as Node)], )} {/if} {/snippet} ``` ### Events Use `onValueChange`, `onHighlightChange`, and `onOpenChange` to respond to state changes. **Example: events** #### React ```tsx import { Portal } from '@ark-ui/react/portal' import { CascadeSelect, createCascadeCollection, useCascadeSelectContext } from '@ark-ui/react/cascade-select' import type { CascadeSelectHighlightChangeDetails, CascadeSelectValueChangeDetails } from '@ark-ui/react/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react' import styles from 'styles/cascade-select.module.css' export const Events = () => { const handleValueChange = (details: CascadeSelectValueChangeDetails) => { console.log('value changed:', details.value, details.items) } const handleHighlightChange = (details: CascadeSelectHighlightChangeDetails) => { console.log('highlight changed:', details.highlightedValue, details.highlightedItems) } const handleOpenChange = (details: { open: boolean }) => { console.log('open changed:', details.open) } return ( Location ) } const TreeNode = ({ node, indexPath = [], value = [] }: { node: Node; indexPath?: number[]; value?: string[] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Solid ```tsx import { CascadeSelect, createCascadeCollection, useCascadeSelectContext, type CascadeSelectHighlightChangeDetails, type CascadeSelectValueChangeDetails, } from '@ark-ui/solid/cascade-select' import { ChevronRightIcon, ChevronsUpDownIcon, XIcon } from 'lucide-solid' import { For, Show } from 'solid-js' import { Portal } from 'solid-js/web' import styles from 'styles/cascade-select.module.css' export const Events = () => { const handleValueChange = (details: CascadeSelectValueChangeDetails) => { console.log('value changed:', details.value, details.items) } const handleHighlightChange = (details: CascadeSelectHighlightChangeDetails) => { console.log('highlight changed:', details.highlightedValue, details.highlightedItems) } const handleOpenChange = (details: { open: boolean }) => { console.log('open changed:', details.open) } return ( Location ) } const TreeNode = (props: { node: Node; indexPath?: number[]; value?: string[] }) => { const context = useCascadeSelectContext() const nodeState = () => context().getItemState({ item: props.node, indexPath: props.indexPath ?? [], value: props.value ?? [] }) return ( <> {(child, getIndex) => ( {collection.stringifyNode(child)} ✓} > )} ) } interface Node { label: string value: string children?: Node[] } const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Americas', value: 'americas', children: [ { label: 'United States', value: 'us', children: [ { label: 'New York', value: 'new-york' }, { label: 'California', value: 'california' }, ], }, ], }, { label: 'Europe', value: 'europe', children: [ { label: 'France', value: 'france', children: [ { label: 'Paris', value: 'paris' }, { label: 'Lyon', value: 'lyon' }, ], }, ], }, ], }, }) ``` #### Vue ```vue ``` #### Svelte ```svelte Location {#snippet render(api)} {@render renderNode(api, collection.rootNode, [], [])} {/snippet} {#snippet renderNode(api: UseCascadeSelectReturn, node: Node, indexPath: number[], value: string[])} {@const nodeState = api().getItemState({ item: node, indexPath, value })} {#each collection.getNodeChildren(node) as child, i} {collection.stringifyNode(child)} {#if collection.isBranchNode(child)} {:else} {/if} {/each} {#if nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild)} {@render renderNode( api, nodeState.highlightedChild as Node, [...indexPath, nodeState.highlightedIndex], [...value, collection.getNodeValue(nodeState.highlightedChild as Node)], )} {/if} {/snippet} ``` ## Guides ### Building the Tree The cascade select uses `createCascadeCollection` to define the hierarchical data. Provide `nodeToValue` and `nodeToString` functions along with the `rootNode` to configure the collection. ```tsx const collection = createCascadeCollection({ nodeToValue: (node) => node.value, nodeToString: (node) => node.label, rootNode: { label: 'Root', value: 'root', children: [ { label: 'Electronics', value: 'electronics', children: [ { label: 'Phones', value: 'phones' }, { label: 'Laptops', value: 'laptops' }, ], }, ], }, }) ``` ### Rendering Panels The cascade select renders one panel per level of depth. Use a recursive component to render the nested lists. Each panel is determined by which item is currently highlighted — use `getItemState` with `highlightedChild` and `highlightedIndex` to recurse into the next level. ```tsx const TreeNode = ({ node, indexPath = [], value = [] }) => { const api = useCascadeSelectContext() const nodeState = api.getItemState({ item: node, indexPath, value }) return ( <> {collection.getNodeChildren(node).map((child, i) => ( {collection.stringifyNode(child)} {collection.isBranchNode(child) ? ( ) : ( )} ))} {nodeState.highlightedChild && collection.isBranchNode(nodeState.highlightedChild) && ( )} ) } ``` ### Hidden Input The `CascadeSelect.HiddenInput` component renders a native `` element that is visually hidden but present in the DOM, enabling native form submission with the selected value. ```tsx {/* Other CascadeSelect components */} ``` ## API Reference ### Props **Component API Reference** #### React **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `TreeCollection` | Yes | The collection of cascade select nodes | | `allowParentSelection` | `boolean` | No | Whether parent (branch) items can be selectable | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `closeOnSelect` | `boolean` | No | Whether the cascade-select should close when an item is selected | | `defaultHighlightedValue` | `string[]` | No | The initial highlighted value of the cascade-select when rendered. | | `defaultOpen` | `boolean` | No | The initial open state of the cascade-select when rendered. Use when you don't need to control the open state. | | `defaultValue` | `string[][]` | No | The initial value of the cascade-select when rendered. Use when you don't need to control the value. | | `disabled` | `boolean` | No | Whether the cascade-select is disabled | | `form` | `string` | No | The form attribute of the underlying input element | | `formatValue` | `(selectedItems: T[][]) => string` | No | Function to format the display value | | `highlightedValue` | `string[]` | No | The controlled highlighted value of the cascade-select | | `highlightTrigger` | `'click' | 'hover'` | No | What triggers highlighting of items | | `id` | `string` | No | The unique identifier of the machine. | | `ids` | `Partial<{ root: string label: string control: string trigger: string indicator: string clearTrigger: string positioner: string content: string hiddenInput: string list(valuePath: string): string item(valuePath: string): string }>` | No | The ids of the cascade-select elements. Useful for composition. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `invalid` | `boolean` | No | Whether the cascade-select is invalid | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loopFocus` | `boolean` | No | Whether the cascade-select should loop focus when navigating with keyboard | | `multiple` | `boolean` | No | Whether to allow multiple selections | | `name` | `string` | No | The name attribute of the underlying input element | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `onFocusOutside` | `(event: FocusOutsideEvent) => void` | No | Function called when the focus is moved outside the component | | `onHighlightChange` | `(details: HighlightChangeDetails) => void` | No | Called when the highlighted value changes | | `onInteractOutside` | `(event: InteractOutsideEvent) => void` | No | Function called when an interaction happens outside the component | | `onOpenChange` | `(details: OpenChangeDetails) => void` | No | Called when the open state changes | | `onPointerDownOutside` | `(event: PointerDownOutsideEvent) => void` | No | Function called when the pointer is pressed down outside the component | | `onValueChange` | `(details: ValueChangeDetails) => void` | No | Called when the value changes | | `open` | `boolean` | No | The controlled open state of the cascade-select | | `positioning` | `PositioningOptions` | No | The positioning options for the cascade-select content | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `readOnly` | `boolean` | No | Whether the cascade-select is read-only | | `required` | `boolean` | No | Whether the cascade-select is required | | `scrollToIndexFn` | `(details: ScrollToIndexDetails) => void` | No | Function to scroll to a specific index in a list | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | | `value` | `string[][]` | No | The controlled value of the cascade-select | **Root Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | root | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **ClearTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ClearTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | clear-trigger | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **Content Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Content Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | content | | `[data-activedescendant]` | The id the active descendant of the content | | `[data-state]` | "open" | "closed" | **Content CSS Variables:** | Variable | Description | |----------|-------------| | `--layer-index` | The index of the dismissable in the layer stack | | `--nested-layer-count` | The number of nested cascade-selects | **Control Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Control Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | control | | `[data-disabled]` | Present when disabled | | `[data-focused]` | | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **HiddenInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | indicator | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-indicator | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-type]` | The type of the item | | `[data-state]` | "checked" | "unchecked" | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item | | `[data-value]` | The value of the item | | `[data-disabled]` | Present when disabled | | `[data-highlighted]` | Present when highlighted | | `[data-selected]` | Present when selected | | `[data-depth]` | The depth of the item | | `[data-state]` | "checked" | "unchecked" | | `[data-type]` | The type of the item | | `[data-index-path]` | | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-text | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-state]` | "checked" | "unchecked" | | `[data-disabled]` | Present when disabled | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Label Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | label | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **List Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | **List Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | list | | `[data-depth]` | The depth of the item | **Positioner Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Positioner CSS Variables:** | Variable | Description | |----------|-------------| | `--reference-width` | The width of the reference element | | `--reference-height` | The height of the root | | `--available-width` | The available width in viewport | | `--available-height` | The available height in viewport | | `--x` | The x position for transform | | `--y` | The y position for transform | | `--z-index` | The z-index value | | `--transform-origin` | The transform origin for animations | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | | `value` | `any` | No | | **Trigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Trigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | trigger | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-focused]` | | | `[data-placement]` | The placement of the trigger | **ValueText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `placeholder` | `string` | No | Text to display when no value is selected. | **ValueText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | value-text | | `[data-disabled]` | Present when disabled | | `[data-invalid]` | Present when invalid | | `[data-focused]` | Present when focused | #### Solid **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `TreeCollection` | Yes | The collection of cascade select nodes | | `allowParentSelection` | `boolean` | No | Whether parent (branch) items can be selectable | | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `closeOnSelect` | `boolean` | No | Whether the cascade-select should close when an item is selected | | `defaultHighlightedValue` | `string[]` | No | The initial highlighted value of the cascade-select when rendered. | | `defaultOpen` | `boolean` | No | The initial open state of the cascade-select when rendered. Use when you don't need to control the open state. | | `defaultValue` | `string[][]` | No | The initial value of the cascade-select when rendered. Use when you don't need to control the value. | | `disabled` | `boolean` | No | Whether the cascade-select is disabled | | `form` | `string` | No | The form attribute of the underlying input element | | `formatValue` | `(selectedItems: T[][]) => string` | No | Function to format the display value | | `highlightedValue` | `string[]` | No | The controlled highlighted value of the cascade-select | | `highlightTrigger` | `'click' | 'hover'` | No | What triggers highlighting of items | | `id` | `string` | No | The unique identifier of the machine. | | `ids` | `Partial<{ root: string label: string control: string trigger: string indicator: string clearTrigger: string positioner: string content: string hiddenInput: string list(valuePath: string): string item(valuePath: string): string }>` | No | The ids of the cascade-select elements. Useful for composition. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `invalid` | `boolean` | No | Whether the cascade-select is invalid | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loopFocus` | `boolean` | No | Whether the cascade-select should loop focus when navigating with keyboard | | `multiple` | `boolean` | No | Whether to allow multiple selections | | `name` | `string` | No | The name attribute of the underlying input element | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `onFocusOutside` | `(event: FocusOutsideEvent) => void` | No | Function called when the focus is moved outside the component | | `onHighlightChange` | `(details: HighlightChangeDetails) => void` | No | Called when the highlighted value changes | | `onInteractOutside` | `(event: InteractOutsideEvent) => void` | No | Function called when an interaction happens outside the component | | `onOpenChange` | `(details: OpenChangeDetails) => void` | No | Called when the open state changes | | `onPointerDownOutside` | `(event: PointerDownOutsideEvent) => void` | No | Function called when the pointer is pressed down outside the component | | `onValueChange` | `(details: ValueChangeDetails) => void` | No | Called when the value changes | | `open` | `boolean` | No | The controlled open state of the cascade-select | | `positioning` | `PositioningOptions` | No | The positioning options for the cascade-select content | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `readOnly` | `boolean` | No | Whether the cascade-select is read-only | | `required` | `boolean` | No | Whether the cascade-select is required | | `scrollToIndexFn` | `(details: ScrollToIndexDetails) => void` | No | Function to scroll to a specific index in a list | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | | `value` | `string[][]` | No | The controlled value of the cascade-select | **Root Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | root | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **ClearTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'button'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ClearTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | clear-trigger | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **Content Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Content Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | content | | `[data-activedescendant]` | The id the active descendant of the content | | `[data-state]` | "open" | "closed" | **Content CSS Variables:** | Variable | Description | |----------|-------------| | `--layer-index` | The index of the dismissable in the layer stack | | `--nested-layer-count` | The number of nested cascade-selects | **Control Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Control Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | control | | `[data-disabled]` | Present when disabled | | `[data-focused]` | | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **HiddenInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'input'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | indicator | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-indicator | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-type]` | The type of the item | | `[data-state]` | "checked" | "unchecked" | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item | | `[data-value]` | The value of the item | | `[data-disabled]` | Present when disabled | | `[data-highlighted]` | Present when highlighted | | `[data-selected]` | Present when selected | | `[data-depth]` | The depth of the item | | `[data-state]` | "checked" | "unchecked" | | `[data-type]` | The type of the item | | `[data-index-path]` | | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-text | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-state]` | "checked" | "unchecked" | | `[data-disabled]` | Present when disabled | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'label'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Label Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | label | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **List Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | **List Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | list | | `[data-depth]` | The depth of the item | **Positioner Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Positioner CSS Variables:** | Variable | Description | |----------|-------------| | `--reference-width` | The width of the reference element | | `--reference-height` | The height of the root | | `--available-width` | The available width in viewport | | `--available-height` | The available height in viewport | | `--x` | The x position for transform | | `--y` | The y position for transform | | `--z-index` | The z-index value | | `--transform-origin` | The transform origin for animations | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `UseCascadeSelectReturn` | Yes | | | `asChild` | `(props: ParentProps<'div'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Trigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'button'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Trigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | trigger | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-focused]` | | | `[data-placement]` | The placement of the trigger | **ValueText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `placeholder` | `string` | No | Text to display when no value is selected. | **ValueText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | value-text | | `[data-disabled]` | Present when disabled | | `[data-invalid]` | Present when invalid | | `[data-focused]` | Present when focused | #### Vue **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `TreeCollection` | Yes | The tree collection data | | `allowParentSelection` | `boolean` | No | Whether parent (branch) items can be selectable | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `closeOnSelect` | `boolean` | No | Whether the cascade-select should close when an item is selected | | `defaultHighlightedValue` | `string[]` | No | The initial highlighted value of the cascade-select when rendered. | | `defaultOpen` | `boolean` | No | The initial open state of the cascade-select when rendered. Use when you don't need to control the open state. | | `defaultValue` | `string[][]` | No | The initial value of the cascade-select when rendered. Use when you don't need to control the value. | | `disabled` | `boolean` | No | Whether the cascade-select is disabled | | `form` | `string` | No | The associate form of the underlying input element | | `formatValue` | `(selectedItems: T[][]) => string` | No | Function to format the display value | | `highlightedValue` | `string[]` | No | The controlled highlighted value of the cascade-select | | `highlightTrigger` | `'click' | 'hover'` | No | What triggers highlighting of items | | `id` | `string` | No | The unique identifier of the machine. | | `ids` | `Partial<{ root: string label: string control: string trigger: string indicator: string clearTrigger: string positioner: string content: string hiddenInput: string list(valuePath: string): string item(valuePath: string): string }>` | No | The ids of the cascade-select elements. Useful for composition. | | `invalid` | `boolean` | No | Whether the cascade-select is invalid | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loopFocus` | `boolean` | No | Whether the cascade-select should loop focus when navigating with keyboard | | `modelValue` | `string[][]` | No | The v-model value of the cascade-select | | `multiple` | `boolean` | No | Whether to allow multiple selections | | `name` | `string` | No | The name attribute of the underlying input element | | `open` | `boolean` | No | The controlled open state of the cascade-select | | `positioning` | `PositioningOptions` | No | The positioning options for the cascade-select content | | `readOnly` | `boolean` | No | Whether the cascade-select is read-only | | `required` | `boolean` | No | Whether the cascade-select is required | | `scrollToIndexFn` | `(details: ScrollToIndexDetails) => void` | No | Function to scroll to a specific index in a list | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Root Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | root | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **ClearTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ClearTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | clear-trigger | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **Content Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Content Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | content | | `[data-activedescendant]` | The id the active descendant of the content | | `[data-state]` | "open" | "closed" | **Content CSS Variables:** | Variable | Description | |----------|-------------| | `--layer-index` | The index of the dismissable in the layer stack | | `--nested-layer-count` | The number of nested cascade-selects | **Control Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Control Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | control | | `[data-disabled]` | Present when disabled | | `[data-focused]` | | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **HiddenInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | indicator | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-indicator | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-type]` | The type of the item | | `[data-state]` | "checked" | "unchecked" | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item | | `[data-value]` | The value of the item | | `[data-disabled]` | Present when disabled | | `[data-highlighted]` | Present when highlighted | | `[data-selected]` | Present when selected | | `[data-depth]` | The depth of the item | | `[data-state]` | "checked" | "unchecked" | | `[data-type]` | The type of the item | | `[data-index-path]` | | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-text | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-state]` | "checked" | "unchecked" | | `[data-disabled]` | Present when disabled | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Label Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | label | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **List Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | **List Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | list | | `[data-depth]` | The depth of the item | **Positioner Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Positioner CSS Variables:** | Variable | Description | |----------|-------------| | `--reference-width` | The width of the reference element | | `--reference-height` | The height of the root | | `--available-width` | The available width in viewport | | `--available-height` | The available height in viewport | | `--x` | The x position for transform | | `--y` | The y position for transform | | `--z-index` | The z-index value | | `--transform-origin` | The transform origin for animations | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | | `value` | `any` | No | | **Trigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Trigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | trigger | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-focused]` | | | `[data-placement]` | The placement of the trigger | **ValueText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `placeholder` | `string` | No | | **ValueText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | value-text | | `[data-disabled]` | Present when disabled | | `[data-invalid]` | Present when invalid | | `[data-focused]` | Present when focused | #### Svelte **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `TreeCollection` | Yes | The collection of cascade select nodes | | `allowParentSelection` | `boolean` | No | Whether parent (branch) items can be selectable | | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `closeOnSelect` | `boolean` | No | Whether the cascade-select should close when an item is selected | | `defaultHighlightedValue` | `string[]` | No | The initial highlighted value of the cascade-select when rendered. | | `defaultOpen` | `boolean` | No | The initial open state of the cascade-select when rendered. Use when you don't need to control the open state. | | `defaultValue` | `string[][]` | No | The initial value of the cascade-select when rendered. Use when you don't need to control the value. | | `disabled` | `boolean` | No | Whether the cascade-select is disabled | | `form` | `string` | No | The form attribute of the underlying input element | | `formatValue` | `(selectedItems: T[][]) => string` | No | Function to format the display value | | `highlightedValue` | `string[]` | No | The controlled highlighted value of the cascade-select | | `highlightTrigger` | `'click' | 'hover'` | No | What triggers highlighting of items | | `id` | `string` | No | The unique identifier of the machine. | | `ids` | `Partial<{ root: string label: string control: string trigger: string indicator: string clearTrigger: string positioner: string content: string hiddenInput: string list(valuePath: string): string item(valuePath: string): string }>` | No | The ids of the cascade-select elements. Useful for composition. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `invalid` | `boolean` | No | Whether the cascade-select is invalid | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loopFocus` | `boolean` | No | Whether the cascade-select should loop focus when navigating with keyboard | | `multiple` | `boolean` | No | Whether to allow multiple selections | | `name` | `string` | No | The name attribute of the underlying input element | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `onFocusOutside` | `(event: FocusOutsideEvent) => void` | No | Function called when the focus is moved outside the component | | `onHighlightChange` | `(details: HighlightChangeDetails) => void` | No | Called when the highlighted value changes | | `onInteractOutside` | `(event: InteractOutsideEvent) => void` | No | Function called when an interaction happens outside the component | | `onOpenChange` | `(details: OpenChangeDetails) => void` | No | Called when the open state changes | | `onPointerDownOutside` | `(event: PointerDownOutsideEvent) => void` | No | Function called when the pointer is pressed down outside the component | | `onValueChange` | `(details: ValueChangeDetails) => void` | No | Called when the value changes | | `open` | `boolean` | No | The controlled open state of the cascade-select | | `positioning` | `PositioningOptions` | No | The positioning options for the cascade-select content | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `readOnly` | `boolean` | No | Whether the cascade-select is read-only | | `ref` | `Element` | No | | | `required` | `boolean` | No | Whether the cascade-select is required | | `scrollToIndexFn` | `(details: ScrollToIndexDetails) => void` | No | Function to scroll to a specific index in a list | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | | `value` | `string[][]` | No | The controlled value of the cascade-select | **Root Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | root | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **ClearTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'button'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **ClearTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | clear-trigger | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **Content Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Content Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | content | | `[data-activedescendant]` | The id the active descendant of the content | | `[data-state]` | "open" | "closed" | **Content CSS Variables:** | Variable | Description | |----------|-------------| | `--layer-index` | The index of the dismissable in the layer stack | | `--nested-layer-count` | The number of nested cascade-selects | **Context Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `render` | `Snippet<[UseCascadeSelectReturn]>` | Yes | | **Control Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Control Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | control | | `[data-disabled]` | Present when disabled | | `[data-focused]` | | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-state]` | "open" | "closed" | **HiddenInput Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'input'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Indicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Indicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | indicator | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **ItemContext Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `render` | `Snippet<[UseCascadeSelectItemContext]>` | Yes | | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-indicator | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-type]` | The type of the item | | `[data-state]` | "checked" | "unchecked" | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | | `ref` | `Element` | No | | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item | | `[data-value]` | The value of the item | | `[data-disabled]` | Present when disabled | | `[data-highlighted]` | Present when highlighted | | `[data-selected]` | Present when selected | | `[data-depth]` | The depth of the item | | `[data-state]` | "checked" | "unchecked" | | `[data-type]` | The type of the item | | `[data-index-path]` | | **ItemText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | item-text | | `[data-value]` | The value of the item | | `[data-highlighted]` | Present when highlighted | | `[data-state]` | "checked" | "unchecked" | | `[data-disabled]` | Present when disabled | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'label'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Label Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | label | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | **List Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `indexPath` | `IndexPath` | Yes | The index path of the item | | `value` | `string[]` | Yes | The value path of the item | | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | | `ref` | `Element` | No | | **List Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | list | | `[data-depth]` | The depth of the item | **Positioner Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Positioner CSS Variables:** | Variable | Description | |----------|-------------| | `--reference-width` | The width of the reference element | | `--reference-height` | The height of the root | | `--available-width` | The available width in viewport | | `--available-height` | The available height in viewport | | `--x` | The x position for transform | | `--y` | The y position for transform | | `--z-index` | The z-index value | | `--transform-origin` | The transform origin for animations | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `UseCascadeSelectReturn` | Yes | | | `asChild` | `Snippet<[PropsFn<'div'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `ref` | `Element` | No | | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Trigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'button'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `ref` | `Element` | No | | **Trigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | trigger | | `[data-state]` | "open" | "closed" | | `[data-disabled]` | Present when disabled | | `[data-readonly]` | Present when read-only | | `[data-invalid]` | Present when invalid | | `[data-focused]` | | | `[data-placement]` | The placement of the trigger | **ValueText Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `placeholder` | `string` | No | | | `ref` | `Element` | No | | **ValueText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | cascade-select | | `[data-part]` | value-text | | `[data-disabled]` | Present when disabled | | `[data-invalid]` | Present when invalid | | `[data-focused]` | Present when focused | ### Context **API:** | Property | Type | Description | |----------|------|-------------| | `collection` | `TreeCollection` | The tree collection data | | `open` | `boolean` | Whether the cascade-select is open | | `focused` | `boolean` | Whether the cascade-select is focused | | `multiple` | `boolean` | Whether the cascade-select allows multiple selections | | `disabled` | `boolean` | Whether the cascade-select is disabled | | `highlightedValue` | `string[]` | The value of the highlighted item | | `highlightedItems` | `V[]` | The items along the highlighted path | | `selectedItems` | `V[][]` | The selected items | | `hasSelectedItems` | `boolean` | Whether there's a selected option | | `empty` | `boolean` | Whether the cascade-select value is empty | | `value` | `string[][]` | The current value of the cascade-select | | `valueAsString` | `string` | The current value as text | | `focus` | `() => void` | Function to focus on the select input | | `reposition` | `(options?: Partial) => void` | Function to set the positioning options of the cascade-select | | `setOpen` | `(open: boolean) => void` | Function to open the cascade-select | | `setHighlightValue` | `(value: string | string[]) => void` | Function to set the highlighted value (path or single value to find) | | `clearHighlightValue` | `() => void` | Function to clear the highlighted value | | `selectValue` | `(value: string[]) => void` | Function to select a value | | `setValue` | `(value: string[][]) => void` | Function to set the value | | `clearValue` | `(value?: string[]) => void` | Function to clear the value | | `getItemState` | `(props: ItemProps) => ItemState` | Returns the state of a cascade-select item | | `getValueTextProps` | `() => T["element"]` | Returns the props for the value text element | ## Accessibility ### Keyboard Support