Skip to main content

Cascader

Cascader is a dropdown menu for selecting a value from a list of options that can be nested.

Import

import { Cascader } from "@sparrowengg/twigs-react";

Usage

Result
Loading...
<Cascader
  placeholder="Search"
  label="Choose Region"
  css={{
    'ul': {
      paddingLeft: '0',
    }
  }}
  data={[
    {
      label: "India",
      value: "india",
      options: [
        {
          label: "North",
          value: "india-north",
          options: [
            {
              label: "Delhi",
              value: "delhi",
            },
            {
              label: "Punjab",
              value: "punjab",
            },
          ],
        },
        {
          label: "South",
          value: "india-south",
          options: [
            {
              label: "Karnataka",
              value: "karnataka",
            },
            {
              label: "Kerala",
              value: "kerala",
              options: [
                {
                  label: "Alappuzha",
                  value: "alappuzha",
                  options: [
                    {
                      label: "Kuttanad",
                      value: "kuttanad",
                    },
                    {
                      label: "Ambalappuzha",
                      value: "ambalappuzha",
                      options: [
                        {
                          label: "North",
                          value: "ambalappuzha-north",
                        },
                        {
                          label: "South",
                          value: "ambalappuzha-south",
                        },
                      ],
                    },
                  ],
                },
                {
                  label: "Kochi",
                  value: "kochi",
                  options: [
                    {
                      label: "Fort Kochi",
                      value: "fort-kochi",
                    },
                    {
                      label: "Marine Drive",
                      value: "marine-drive",
                    },
                  ],
                },
              ],
            },
          ],
        },
      ],
    },
    {
      label: "USA",
      value: "usa",
      options: [
        {
          label: "Northeast",
          value: "usa-northeast",
          options: [
            {
              label: "New York",
              value: "new-york",
            },
            {
              label: "Massachusetts",
              value: "massachusetts",
            },
          ],
        },
        {
          label: "South",
          value: "usa-south",
          options: [
            {
              label: "Texas",
              value: "texas",
              options: [
                {
                  label: "Houston",
                  value: "houston",
                  options: [
                    {
                      label: "Downtown",
                      value: "downtown-houston",
                    },
                    {
                      label: "The Woodlands",
                      value: "the-woodlands",
                    },
                  ],
                },
                {
                  label: "Austin",
                  value: "austin",
                },
              ],
            },
            {
              label: "Florida",
              value: "florida",
            },
          ],
        },
        {
          label: "West",
          value: "usa-west",
        },
        {
          label: "Midwest",
          value: "usa-midwest",
          options: [
            {
              label: "Illinois",
              value: "illinois",
            },
            {
              label: "Ohio",
              value: "ohio",
            },
          ],
        },
      ],
    },
    {
      label: "Canada",
      value: "canada",
      options: [
        {
          label: "Western Canada",
          value: "western-canada",
        },
        {
          label: "Central Canada",
          value: "central-canada",
        },
        {
          label: "Atlantic Canada",
          value: "atlantic-canada",
        },
        {
          label: "Northern Canada",
          value: "northern-canada",
        },
      ],
    },
  ]}
/>

Props

Types

type CascaderOption = {
label: string;
value: string;
options?: CascaderOption[];
shouldFetchOptions?: boolean;
disabled?: boolean;
isNew?: boolean;
} & Record<string, any>;
PropertyDescriptionTypeDefault
dataData source for Cascader. Array of nested options that form the hierarchical structureCascaderOption[]
valueControlled selected value. Can be a string (value) or object with label and valuestring \| { label: string; value: string }
defaultValueDefault selected value for uncontrolled usagestring \| { label: string; value: string }
onChangeCallback function triggered when selection changes(value: CascaderOption, selectionPath: CascaderOption[]) => void
labelLabel for the input fieldstring
placeholderInput placeholder textstring
cssCustom CSS styles for the componentComponentProps<typeof Box>['css']
cancelButtonTextText for the cancel button in the popover footerstring"Cancel"
chooseButtonTextText for the choose button in the popover footerstring"Choose"
inputAriaDescriptionAria description for the input field to provide additional context for screen readersstring
ariaLiveContentFunction to customize screen reader announcements during navigation(data: { breadcrumb: string; label: string; totalItems: number; itemPosition: number; hasOptions: boolean; hasParent: boolean; } \| null) => ReactNode
creatableEnable creation of new options by typing values not in the existing databooleanfalse
popoverPortalPortal container for the popover contentHTMLElement
renderValueCustom component to replace the entire selected value display(value: CascaderOption \| null, selectionPath: CascaderOption[]) => ReactNode
renderValueTextCustom component to replace just the text portion of the selected value(value: CascaderOption \| null, selectionPath: CascaderOption[]) => ReactNode
renderBreadCrumbCustom component to replace the breadcrumb shown below the input(value: CascaderOption \| null, selectionPath: CascaderOption[]) => ReactNode
fetchOptionsAsync function to load child options for a given option. Set shouldFetchOptions: true on options that need dynamic loading(data: CascaderOption) => Promise<void>
fetchSearchOptionsAsync function to load options based on search query. Enables dynamic search functionality(searchQuery: string) => Promise<void>
searchLoadingIndicatorLoading indicator shown during search operationsReactNode"Loading Results..."

Examples

Basic Usage with Static Data

import { Cascader } from "@sparrowengg/twigs-react";

const data = [
{
label: "India",
value: "india",
options: [
{
label: "North",
value: "north",
options: [
{ label: "Delhi", value: "delhi" },
{ label: "Punjab", value: "punjab" }
]
}
]
}
];

<Cascader
data={data}
placeholder="Select location"
label="Location"
onChange={(value, selectionPath) => {
console.log("Selected:", value);
console.log("Path:", selectionPath);
}}
/>

Controlled Component

const [selectedValue, setSelectedValue] = useState({
label: "Delhi",
value: "delhi"
});

<Cascader
data={data}
value={selectedValue}
onChange={(value) => setSelectedValue(value)}
/>

Custom Value Rendering

<Cascader
data={data}
renderValueText={(value, selectionPath) => (
<div>
{selectionPath.map((item, index) => (
<span key={item.value}>
{item.label}
{index < selectionPath.length - 1 && " > "}
</span>
))}
</div>
)}
renderBreadCrumb={() => null} // Hide default breadcrumb
/>

Dynamic Data Loading

const [data, setData] = useState([
{
label: "Dynamic Country",
value: "dynamic",
shouldFetchOptions: true // Mark for dynamic loading
}
]);

<Cascader
data={data}
fetchOptions={async (option) => {
// Simulate API call
const newOptions = await fetchChildOptions(option.value);

// Update the data state with new options
const updatedData = [...data];
const targetOption = findOptionInData(updatedData, option.value);
targetOption.options = newOptions;
setData(updatedData);
}}
/>

Creatable Options

const [data, setData] = useState(initialData);
const [value, setValue] = useState(null);

<Cascader
data={data}
value={value}
creatable
onChange={(val) => {
if (val.isNew) {
// Add new option to data
setData([
...data,
{
label: val.label,
value: val.value,
options: []
}
]);
}
setValue(val);
}}
/>

Disabled Options

const dataWithDisabled = [
{
label: "Available Option",
value: "available"
},
{
label: "Disabled Option",
value: "disabled",
disabled: true // This option will be unselectable
}
];

<Cascader data={dataWithDisabled} />
<Cascader
data={data}
fetchSearchOptions={async (searchQuery) => {
// Fetch search results from API
const searchResults = await searchAPI(searchQuery);

// Update data with search results
// Implementation depends on your data structure
updateDataWithSearchResults(searchResults);
}}
searchLoadingIndicator={<div>Searching...</div>}
/>