A comprehensive cascading select component for React applications that enables hierarchical option selection through a dropdown interface
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Multiple selection capabilities with checkbox support, different display strategies, and hierarchical selection management. Enables users to select multiple items across different levels of the cascading hierarchy.
Enable and configure multiple selection behavior.
interface MultipleSelectionProps<
OptionType extends DefaultOptionType,
ValueField extends keyof OptionType
> {
/** Enable multiple selection mode */
checkable: true | React.ReactNode;
/** Strategy for displaying selected items */
showCheckedStrategy?: ShowCheckedStrategy;
/** Clear search value when selecting an item */
autoClearSearchValue?: boolean;
/** Multiple selection value type */
value?: (string | number)[][];
/** Multiple selection change handler */
onChange?: (
value: (string | number)[][],
selectOptions: OptionType[][]
) => void;
}Control how selected items are displayed in multiple selection mode.
type ShowCheckedStrategy = 'SHOW_PARENT' | 'SHOW_CHILD';
// Available as constants on Cascader component
Cascader.SHOW_PARENT: 'SHOW_PARENT';
Cascader.SHOW_CHILD: 'SHOW_CHILD';
// Access via destructuring
const { SHOW_PARENT, SHOW_CHILD } = Cascader;Type definitions for multiple selection values and callbacks.
/** Multiple selection value format - array of value paths */
type MultipleValueType = (string | number)[][];
/** Multiple selection options format - array of option paths */
type MultipleOptionsType<OptionType> = OptionType[][];
/** Multiple selection change callback */
interface MultipleChangeCallback<OptionType> {
(value: MultipleValueType, selectOptions: MultipleOptionsType<OptionType>): void;
}Configure checkbox behavior for individual options.
interface CheckboxOptionType extends BaseOptionType {
/** Disable checkbox for this specific option */
disableCheckbox?: boolean;
/** Disable the entire option (selection and checkbox) */
disabled?: boolean;
}import React, { useState } from 'react';
import Cascader from 'rc-cascader';
const options = [
{
label: 'Technology',
value: 'tech',
children: [
{
label: 'Frontend',
value: 'frontend',
children: [
{ label: 'React', value: 'react' },
{ label: 'Vue', value: 'vue' },
{ label: 'Angular', value: 'angular' }
]
},
{
label: 'Backend',
value: 'backend',
children: [
{ label: 'Node.js', value: 'nodejs' },
{ label: 'Python', value: 'python' }
]
}
]
}
];
const BasicMultipleExample = () => {
const [value, setValue] = useState([]);
const onChange = (value, selectedOptions) => {
console.log('Selected values:', value);
console.log('Selected options:', selectedOptions);
setValue(value);
};
return (
<Cascader
checkable
options={options}
value={value}
onChange={onChange}
placeholder="Select multiple technologies"
style={{ width: 300 }}
/>
);
};Display only parent items when all children are selected.
const ShowParentExample = () => {
const [value, setValue] = useState([]);
return (
<Cascader
checkable
options={options}
value={value}
onChange={setValue}
showCheckedStrategy={Cascader.SHOW_PARENT}
placeholder="Show parent strategy"
/>
);
};Always display individual selected items, never parent groups.
const ShowChildExample = () => {
const [value, setValue] = useState([]);
return (
<Cascader
checkable
options={options}
value={value}
onChange={setValue}
showCheckedStrategy={Cascader.SHOW_CHILD}
placeholder="Show child strategy"
/>
);
};const CustomCheckboxExample = () => {
const [value, setValue] = useState([]);
return (
<Cascader
checkable={<span style={{ color: 'blue' }}>✓</span>}
options={options}
value={value}
onChange={setValue}
placeholder="Custom checkbox icon"
/>
);
};const ControlledMultipleExample = () => {
const [value, setValue] = useState([
['tech', 'frontend', 'react'],
['tech', 'backend', 'nodejs']
]);
const handleChange = (newValue, selectedOptions) => {
console.log('Value changed from:', value);
console.log('Value changed to:', newValue);
setValue(newValue);
};
const handleClear = () => {
setValue([]);
};
return (
<div>
<Cascader
checkable
options={options}
value={value}
onChange={handleChange}
placeholder="Controlled selection"
/>
<button onClick={handleClear} style={{ marginLeft: 8 }}>
Clear All
</button>
<div style={{ marginTop: 8 }}>
Selected: {JSON.stringify(value, null, 2)}
</div>
</div>
);
};const disabledOptions = [
{
label: 'Skills',
value: 'skills',
children: [
{
label: 'Programming',
value: 'programming',
disableCheckbox: true, // Can't select this level
children: [
{ label: 'JavaScript', value: 'js' },
{ label: 'Python', value: 'python', disabled: true }, // Completely disabled
{ label: 'Java', value: 'java' }
]
},
{
label: 'Design',
value: 'design',
children: [
{ label: 'UI Design', value: 'ui' },
{ label: 'UX Design', value: 'ux', disableCheckbox: true }
]
}
]
}
];
const DisabledCheckboxExample = () => {
const [value, setValue] = useState([]);
return (
<Cascader
checkable
options={disabledOptions}
value={value}
onChange={setValue}
placeholder="Some checkboxes disabled"
/>
);
};const MultipleWithSearchExample = () => {
const [value, setValue] = useState([]);
return (
<Cascader
checkable
options={options}
value={value}
onChange={setValue}
showSearch
autoClearSearchValue={false} // Keep search text after selection
placeholder="Multiple selection with search"
style={{ width: 400 }}
/>
);
};const DynamicMultipleExample = () => {
const [options, setOptions] = useState([
{
label: 'Categories',
value: 'categories',
isLeaf: false
}
]);
const [value, setValue] = useState([]);
const loadData = (selectedOptions) => {
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
setTimeout(() => {
targetOption.loading = false;
targetOption.children = [
{ label: 'Sub Category 1', value: 'sub1' },
{ label: 'Sub Category 2', value: 'sub2', disableCheckbox: true },
{ label: 'Sub Category 3', value: 'sub3' }
];
setOptions([...options]);
}, 1000);
};
return (
<Cascader
checkable
options={options}
value={value}
onChange={setValue}
loadData={loadData}
changeOnSelect
placeholder="Dynamic multiple selection"
/>
);
};const CustomDisplayMultipleExample = () => {
const [value, setValue] = useState([]);
const displayRender = (labels, selectedOptions) => {
if (labels.length === 0) return 'Select items';
if (labels.length <= 2) {
return labels.map(labelArray => labelArray.join(' > ')).join(', ');
}
return `${labels.length} items selected`;
};
return (
<Cascader
checkable
options={options}
value={value}
onChange={setValue}
displayRender={displayRender}
placeholder="Custom display rendering"
style={{ width: 300 }}
/>
);
};const FormMultipleExample = () => {
const [formData, setFormData] = useState({
skills: [],
interests: []
});
const handleSkillsChange = (value, selectedOptions) => {
setFormData(prev => ({
...prev,
skills: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form data:', formData);
};
return (
<form onSubmit={handleSubmit}>
<div style={{ marginBottom: 16 }}>
<label>Skills:</label>
<Cascader
checkable
options={skillsOptions}
value={formData.skills}
onChange={handleSkillsChange}
showCheckedStrategy={Cascader.SHOW_CHILD}
placeholder="Select your skills"
style={{ width: '100%', marginTop: 4 }}
/>
</div>
<div style={{ marginBottom: 16 }}>
<label>Interests:</label>
<Cascader
checkable
options={interestsOptions}
value={formData.interests}
onChange={(value) =>
setFormData(prev => ({ ...prev, interests: value }))
}
placeholder="Select your interests"
style={{ width: '100%', marginTop: 4 }}
/>
</div>
<button type="submit">Submit</button>
</form>
);
};const ValidationMultipleExample = () => {
const [value, setValue] = useState([]);
const [error, setError] = useState('');
const handleChange = (newValue, selectedOptions) => {
setValue(newValue);
// Validation logic
if (newValue.length === 0) {
setError('Please select at least one item');
} else if (newValue.length > 5) {
setError('Maximum 5 items can be selected');
} else {
setError('');
}
};
return (
<div>
<Cascader
checkable
options={options}
value={value}
onChange={handleChange}
placeholder="Select 1-5 items"
style={{
width: 300,
borderColor: error ? 'red' : undefined
}}
/>
{error && (
<div style={{ color: 'red', fontSize: '12px', marginTop: 4 }}>
{error}
</div>
)}
<div style={{ marginTop: 8, fontSize: '12px', color: '#666' }}>
Selected: {value.length}/5
</div>
</div>
);
};Install with Tessl CLI
npx tessl i tessl/npm-rc-cascader