> Leaf UI 0.6.0 · Package: @ifhover/leaf-ui · Source: b30c3d3a8fa9c5e15d0d0522cebfbd33f60c6b06
> Browser documentation: https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/cascader.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms-full.txt.

# Cascader

Choose a value through a hierarchy of options.

## Examples

A selection is committed at a leaf option. onChange supplies both the path and its options. Named fields submit a JSON array string. Use arrow keys to navigate levels, Enter to choose and Escape to close.


Project category

Choose a category

Default category

Design / Interface design

Disabled category

Please select

basic.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/cascader/basic.tsx"
import { Cascader, Form, FormField } from '@ifhover/leaf-ui';

const options = [
  {
    value: 'design',
    label: 'Design',
    children: [
      { value: 'interface', label: 'Interface design' },
      { value: 'brand', label: 'Brand design' },
    ],
  },
  {
    value: 'engineering',
    label: 'Engineering',
    children: [
      { value: 'frontend', label: 'Frontend development' },
      { value: 'backend', label: 'Backend development' },
    ],
  },
  { value: 'archived', label: 'Archived category', disabled: true },
];

export function CascaderBasic() {
  return (
    <Form layout="vertical">
      <FormField label="Project category">
        <Cascader aria-label="Project category" options={options} placeholder="Choose a category" />
      </FormField>
      <FormField label="Default category">
        <Cascader
          aria-label="Default category"
          options={options}
          defaultValue={['design', 'interface']}
        />
      </FormField>
      <FormField label="Disabled category">
        <Cascader aria-label="Disabled category" options={options} disabled />
      </FormField>
    </Form>
  );
}
```

Expand code


Delivery region

Zhejiang / Hangzhou / Xihu

Selected path:zhejiang → hangzhou → xihu

controlled.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/cascader/controlled.tsx"
import { Cascader, Form, FormField, Text } from '@ifhover/leaf-ui';

import { useState } from 'react';

import { regions } from './options';

export function CascaderControlled() {
  const [value, setValue] = useState<string[]>(['zhejiang', 'hangzhou', 'xihu']);
  return (
    <Form layout="vertical">
      <FormField label="Delivery region">
        <Cascader
          aria-label="Delivery region"
          options={regions}
          value={value}
          onChange={setValue}
        />
      </FormField>
      <Text tone="muted">Selected path:{value.join(' → ') || 'Not selected'}</Text>
    </Form>
  );
}
```

Expand code

## Search, multiple paths and lazy loading


Search, multiple paths and intermediate levels

Please select

Lazy loading and explicit cache refresh

Please select

Refresh data

capabilities.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/cascader/capabilities.tsx"
import type { CascaderOption } from '@ifhover/leaf-ui';

import { Button, Cascader, Flex, Space, Text } from '@ifhover/leaf-ui';

import { useCallback, useState } from 'react';

const options = [
  {
    value: 'product',
    label: 'Product',
    children: [
      { value: 'ui', label: 'UI' },
      { value: 'web', label: 'Web' },
    ],
  },
  { value: 'team', label: 'Team', children: [{ value: 'design', label: 'Design' }] },
];

const lazy: CascaderOption[] = [{ value: 'remote', label: 'Remote', isLeaf: false }];

export function Capabilities() {
  const [version, setVersion] = useState(0);
  const load = useCallback(async (option: CascaderOption, signal: AbortSignal) => {
    await new Promise<void>((resolve, reject) => {
      const timer = setTimeout(resolve, 350);
      signal.addEventListener(
        'abort',
        () => {
          clearTimeout(timer);
          reject(signal.reason);
        },
        { once: true },
      );
    });
    return [{ value: `${option.value}-child`, label: 'Loaded item', isLeaf: true }];
  }, []);
  return (
    <Space direction="vertical" align="stretch">
      <Flex direction="column" gap="sm" align="center">
        <Text>
          {'Search, multiple paths and intermediate levels'}
        </Text>
        <Cascader options={options} showSearch multiple changeOnSelect />
      </Flex>
      <Flex direction="column" gap="sm" align="center">
        <Text>{'Lazy loading and explicit cache refresh'}</Text>
        <Cascader options={lazy} loadData={load} cacheKey={version} allowClear />
      </Flex>
      <Button variant="outline" onClick={() => setVersion(version + 1)}>
        {'Refresh data'}
      </Button>
    </Space>
  );
}
```

Expand code

## Single-line selections

Set `tagWrap={false}` to keep selected values on one line. Long labels truncate; extra values collapse into `+N`. In very narrow controls, only the count is shown. Open the popup to review or change selections. `maxTagCount` can further limit the visible tags; `maxTagCount="responsive"` also enables automatic single-line collapsing.


Product / Experience designProduct / Web developmentProduct / Mobile development+3

single-line.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/cascader/single-line.tsx"
import { Cascader } from '@ifhover/leaf-ui';

const options = [
  {
    value: 'product',
    label: 'Product',
    children: [
      { value: 'design', label: 'Experience design' },
      { value: 'web', label: 'Web development' },
      { value: 'mobile', label: 'Mobile development' },
    ],
  },
];

export function SingleLine() {
  return (
    <Cascader
      aria-label="Product teams"
      multiple
      showSearch
      tagWrap={false}
      options={options}
      defaultValue={[
        ['product', 'design'],
        ['product', 'web'],
        ['product', 'mobile'],
      ]}
    />
  );
}
```

Expand code

## Cascader API

| Property            | Type                                                                                                                                                                                 | Default        | Description                                                                        |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- | ---------------------------------------------------------------------------------- |
| `popupPlacement`    | `'top' \| 'top-start' \| 'top-end' \| 'bottom' \| 'bottom-start' \| 'bottom-end' \| 'left' \| 'left-start' \| 'left-end' \| 'right' \| 'right-start' \| 'right-end'`                 | —              | Placement relative to the trigger.                                                 |
| `popupClassName`    | `string`                                                                                                                                                                             | —              | Custom class for the popup.                                                        |
| `popupStyle`        | `CSSProperties`                                                                                                                                                                      | —              | Custom popup styles.                                                               |
| `popupRender`       | `(content: React.ReactNode) => React.ReactNode`                                                                                                                                      | —              | Wrap or extend popup content; retain the supplied content to preserve interaction. |
| `getPopupContainer` | `() => Element \| DocumentFragment`                                                                                                                                                  | —              | Return a popup container, including a ShadowRoot.                                  |
| `options`           | `readonly `[`CascaderOption`](#cascaderoption)`[]`                                                                                                                                   | Required       | Required. Hierarchical options                                                     |
| `size`              | `'sm' \| 'md' \| 'lg'`                                                                                                                                                               | `'md'`         | Control size                                                                       |
| `status`            | `'error' \| 'warning'`                                                                                                                                                               | —              | Validation appearance                                                              |
| `placeholder`       | `string`                                                                                                                                                                             | Locale default | Placeholder when empty; localized by ConfigProvider                                |
| `name`              | `string`                                                                                                                                                                             | —              | Field name / associated form ID                                                    |
| `required`          | `boolean`                                                                                                                                                                            | `false`        | Require a non-empty value; compound controls validate once.                        |
| `allowClear`        | `boolean`                                                                                                                                                                            | `true`         | Clearing returns two empty arrays                                                  |
| `onOpenChange`      | `(open: boolean) => void`                                                                                                                                                            | —              | Panel open-state changes                                                           |
| `open`              | `boolean`                                                                                                                                                                            | —              | Control whether the panel is open.                                                 |
| `defaultOpen`       | `boolean`                                                                                                                                                                            | —              | Initial open state.                                                                |
| `readOnly`          | `boolean`                                                                                                                                                                            | —              | Lock the value against typing, selection, clearing and removal.                    |
| `showSearch`        | `boolean`                                                                                                                                                                            | —              | Enable search input.                                                               |
| `changeOnSelect`    | `boolean`                                                                                                                                                                            | —              | Allow selecting intermediate levels.                                               |
| `displayRender`     | `(labels: ReactNode[], selectedOptions: `[`CascaderOption`](#cascaderoption)`[]) => ReactNode`                                                                                       | —              | Customize displayed paths.                                                         |
| `optionRender`      | `(option: `[`CascaderOption`](#cascaderoption)`) => ReactNode`                                                                                                                       | —              | Customize option content.                                                          |
| `loadData`          | `(option: `[`CascaderOption`](#cascaderoption)`, signal: AbortSignal) => Promise<readonly `[`CascaderOption`](#cascaderoption)`[]>`                                                  | —              | Load child nodes asynchronously and respect AbortSignal.                           |
| `onLoadError`       | `(error: unknown, option: `[`CascaderOption`](#cascaderoption)`) => void`                                                                                                            | —              | Called on loading failure, for retry feedback.                                     |
| `cacheKey`          | `string \| number`                                                                                                                                                                   | —              | Changing the data version clears lazy caches and cancels stale requests.           |
| `tagWrap`           | `boolean`                                                                                                                                                                            | `true`         | Allow selected tags to wrap; false keeps one line and collapses overflow.          |
| `maxTagCount`       | `number \| 'responsive'`                                                                                                                                                             | —              | Maximum visible tags; responsive collapses them to the available width.            |
| `multiple`          | `false \| true`                                                                                                                                                                      | `false`        | Enable multiple selection; value and callback types change accordingly.            |
| `value`             | `readonly string[] \| readonly (readonly string[])[]`                                                                                                                                | Required       | Value; unique at the same level                                                    |
| `defaultValue`      | `readonly string[] \| readonly (readonly string[])[]`                                                                                                                                | `[]`           | Controlled path / initial uncontrolled path                                        |
| `onChange`          | `((value: string[], selectedOptions: `[`CascaderOption`](#cascaderoption)`[]) => void) \| ((value: string[][], selectedOptions: `[`CascaderOption`](#cascaderoption)`[][]) => void)` | —              | Runs when a leaf is selected or the path is cleared                                |
| `disabled`          | `boolean`                                                                                                                                                                            | `false`        | Disable interaction.                                                               |
| `form`              | `string`                                                                                                                                                                             | —              | ID of the associated native form.                                                  |
| `ref`               | `Ref<HTMLButtonElement>`                                                                                                                                                             | —              | DOM reference                                                                      |
| `children`          | [`readonly CascaderOption[]`](#cascaderoption)                                                                                                                                       | —              | Content, or child nodes for hierarchical records.                                  |

### CascaderOption

| Property   | Type                                           | Default  | Description                                               |
| ---------- | ---------------------------------------------- | -------- | --------------------------------------------------------- |
| `value`    | `string`                                       | Required | Value; unique at the same level                           |
| `label`    | `string`                                       | Required | Option label                                              |
| `disabled` | `boolean`                                      | `false`  | Disable this option and its descendants                   |
| `children` | [`readonly CascaderOption[]`](#cascaderoption) | —        | Child options; an option without children can be selected |

## Types

Import CascaderProps to describe component props. Option types in the API table link to their detailed fields above.

```ts
import type { CascaderProps, CascaderOption } from '@ifhover/leaf-ui';
```

## Forms and localization

Use name to include values in FormData. Uncontrolled fields follow form reset; reset controlled values in application state. Place controls in [FormField](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/form.md#formfield-api) for labels, help and errors. [ConfigProvider](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/config-provider.md) supplies regional themes and translated built-in UI. Application labels and options are your responsibility.

## CascaderOption

| Property      | Type                                               | Default | Description                                       |
| ------------- | -------------------------------------------------- | ------- | ------------------------------------------------- |
| `value`       | `string`                                           | —       | Required. Controlled value.                       |
| `label`       | `ReactNode`                                        | —       | Required. Visible label or content.               |
| `searchLabel` | `string`                                           | —       | Plain text used for searching.                    |
| `isLeaf`      | `boolean`                                          | —       | Identify a leaf node, including in lazy data.     |
| `disabled`    | `boolean`                                          | —       | Disable interaction.                              |
| `children`    | `readonly `[`CascaderOption`](#cascaderoption)`[]` | —       | Content, or child nodes for hierarchical records. |

## CascaderFieldNames

| Property   | Type     | Default | Description                                       |
| ---------- | -------- | ------- | ------------------------------------------------- |
| `value`    | `string` | —       | Controlled value.                                 |
| `label`    | `string` | —       | Visible label or content.                         |
| `children` | `string` | —       | Content, or child nodes for hierarchical records. |
| `disabled` | `string` | —       | Disable interaction.                              |
| `isLeaf`   | `string` | —       | Identify a leaf node, including in lazy data.     |
