Tree UI component for React with selection, checkboxes, drag-drop, and virtual scrolling features
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
RC Tree provides comprehensive selection and checking functionality with support for single/multiple selection, checkbox hierarchies, and strict/non-strict checking modes.
Node selection system supporting both single and multiple selection modes with full event handling.
/**
* Selection configuration and event handling
*/
interface SelectionConfig<TreeDataType extends BasicDataNode = DataNode> {
/** Enable node selection */
selectable?: boolean;
/** Allow multiple node selection */
multiple?: boolean;
/** Currently selected node keys (controlled) */
selectedKeys?: Key[];
/** Default selected keys (uncontrolled) */
defaultSelectedKeys?: Key[];
/** Currently active/focused node key */
activeKey?: Key | null;
/** Selection change event handler */
onSelect?: (
selectedKeys: Key[],
info: {
event: 'select';
selected: boolean;
node: EventDataNode<TreeDataType>;
selectedNodes: TreeDataType[];
nativeEvent: MouseEvent;
},
) => void;
/** Active node change handler (internal) */
onActiveChange?: (key: Key) => void;
}Comprehensive checkbox system with hierarchical checking and strict/non-strict modes.
/**
* Checkbox configuration and event handling
*/
interface CheckboxConfig<TreeDataType extends BasicDataNode = DataNode> {
/** Enable checkboxes (true/false or custom checkbox element) */
checkable?: boolean | React.ReactNode;
/** Independent checking (parent-child relationship disabled) */
checkStrictly?: boolean;
/** Currently checked keys (controlled) */
checkedKeys?: Key[] | { checked: Key[]; halfChecked: Key[] };
/** Default checked keys (uncontrolled) */
defaultCheckedKeys?: Key[];
/** Check state change event handler */
onCheck?: (
checked: { checked: Key[]; halfChecked: Key[] } | Key[],
info: CheckInfo<TreeDataType>,
) => void;
}
/**
* Detailed information provided in check events
*/
interface CheckInfo<TreeDataType extends BasicDataNode = DataNode> {
/** Event type identifier */
event: 'check';
/** The node that was checked/unchecked */
node: EventDataNode<TreeDataType>;
/** New checked state of the node */
checked: boolean;
/** Native mouse event */
nativeEvent: MouseEvent;
/** Array of all checked node data */
checkedNodes: TreeDataType[];
/** Array of checked nodes with their positions */
checkedNodesPositions?: { node: TreeDataType; pos: string }[];
/** Keys of half-checked (indeterminate) nodes */
halfCheckedKeys?: Key[];
}Usage Examples:
import React, { useState } from "react";
import Tree, { TreeNode } from "rc-tree";
const BasicSelection = () => {
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
return (
<Tree
prefixCls="rc-tree"
selectable
selectedKeys={selectedKeys}
onSelect={(keys, info) => {
console.log('Selected:', keys, 'Node:', info.node);
setSelectedKeys(keys);
}}
>
<TreeNode key="0-0" title="Parent Node">
<TreeNode key="0-0-0" title="Child 1" />
<TreeNode key="0-0-1" title="Child 2" />
</TreeNode>
</Tree>
);
};import React, { useState } from "react";
import Tree from "rc-tree";
const MultipleSelection = () => {
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const treeData = [
{
key: '0-0',
title: 'Parent Node',
children: [
{ key: '0-0-0', title: 'Child 1' },
{ key: '0-0-1', title: 'Child 2' },
{ key: '0-0-2', title: 'Child 3' },
],
},
];
return (
<Tree
prefixCls="rc-tree"
selectable
multiple
treeData={treeData}
selectedKeys={selectedKeys}
onSelect={(keys, info) => {
console.log('Selected keys:', keys);
console.log('Selection info:', info);
setSelectedKeys(keys);
}}
defaultExpandAll
/>
);
};import React, { useState } from "react";
import Tree from "rc-tree";
const BasicCheckbox = () => {
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const treeData = [
{
key: '0-0',
title: 'All Items',
children: [
{ key: '0-0-0', title: 'Item 1' },
{ key: '0-0-1', title: 'Item 2' },
{ key: '0-0-2', title: 'Item 3' },
],
},
];
return (
<Tree
prefixCls="rc-tree"
checkable
treeData={treeData}
checkedKeys={checkedKeys}
onCheck={(checked, info) => {
console.log('Checked:', checked);
console.log('Check info:', info);
// Handle both array and object formats
const keys = Array.isArray(checked) ? checked : checked.checked;
setCheckedKeys(keys);
}}
defaultExpandAll
/>
);
};import React, { useState } from "react";
import Tree from "rc-tree";
const StrictCheckbox = () => {
const [checkedKeys, setCheckedKeys] = useState<{
checked: string[];
halfChecked: string[];
}>({
checked: [],
halfChecked: [],
});
const treeData = [
{
key: '0-0',
title: 'Parent (independent)',
children: [
{ key: '0-0-0', title: 'Child 1 (independent)' },
{ key: '0-0-1', title: 'Child 2 (independent)' },
],
},
];
return (
<Tree
prefixCls="rc-tree"
checkable
checkStrictly // Independent checking
treeData={treeData}
checkedKeys={checkedKeys}
onCheck={(checked, info) => {
console.log('Strict checked:', checked);
console.log('Check info:', info);
// In strict mode, checked is always an object
const keys = checked as { checked: string[]; halfChecked: string[] };
setCheckedKeys(keys);
}}
defaultExpandAll
/>
);
};import React, { useState } from "react";
import Tree from "rc-tree";
const CustomCheckbox = () => {
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const customCheckbox = (
<span style={{
display: 'inline-block',
width: 16,
height: 16,
background: '#f0f0f0',
border: '1px solid #ccc',
borderRadius: 2,
}}>
✓
</span>
);
const treeData = [
{
key: '0-0',
title: 'Custom Checkbox Parent',
children: [
{ key: '0-0-0', title: 'Custom Child 1' },
{ key: '0-0-1', title: 'Custom Child 2' },
],
},
];
return (
<Tree
prefixCls="rc-tree"
checkable={customCheckbox}
treeData={treeData}
checkedKeys={checkedKeys}
onCheck={(checked) => {
const keys = Array.isArray(checked) ? checked : checked.checked;
setCheckedKeys(keys);
}}
defaultExpandAll
/>
);
};import React, { useState } from "react";
import Tree from "rc-tree";
const MixedSelectionChecking = () => {
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const treeData = [
{
key: '0-0',
title: 'Documents',
children: [
{ key: '0-0-0', title: 'Important.pdf' },
{ key: '0-0-1', title: 'Report.docx' },
{ key: '0-0-2', title: 'Archive',
children: [
{ key: '0-0-2-0', title: 'Old File 1.txt' },
{ key: '0-0-2-1', title: 'Old File 2.txt' },
],
},
],
},
];
return (
<div>
<h3>File Browser (Select to view, Check to process)</h3>
<Tree
prefixCls="rc-tree"
selectable
multiple
checkable
treeData={treeData}
selectedKeys={selectedKeys}
checkedKeys={checkedKeys}
onSelect={(keys, info) => {
console.log('Viewing files:', keys);
setSelectedKeys(keys);
}}
onCheck={(checked, info) => {
console.log('Files selected for processing:', checked);
const keys = Array.isArray(checked) ? checked : checked.checked;
setCheckedKeys(keys);
}}
defaultExpandAll
/>
<div style={{ marginTop: 16 }}>
<p>Currently viewing: {selectedKeys.join(', ') || 'None'}</p>
<p>Selected for processing: {checkedKeys.join(', ') || 'None'}</p>
</div>
</div>
);
};/**
* Per-node selection configuration
*/
interface NodeSelectionConfig {
/** Whether this specific node can be selected */
selectable?: boolean;
/** Whether this specific node is disabled */
disabled?: boolean;
}import React, { useState } from "react";
import Tree from "rc-tree";
const CustomSelectionLogic = () => {
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const treeData = [
{
key: '0-0',
title: 'Folders (selectable)',
selectable: true,
children: [
{ key: '0-0-0', title: 'Files (not selectable)', selectable: false },
{ key: '0-0-1', title: 'Another File', selectable: false },
],
},
{
key: '0-1',
title: 'Disabled Folder',
disabled: true,
children: [
{ key: '0-1-0', title: 'Disabled Child', disabled: true },
],
},
];
return (
<Tree
prefixCls="rc-tree"
selectable
multiple
treeData={treeData}
selectedKeys={selectedKeys}
onSelect={(keys, info) => {
console.log('Custom selection:', keys, info);
setSelectedKeys(keys);
}}
defaultExpandAll
/>
);
};/**
* Per-node checkbox configuration
*/
interface NodeCheckboxConfig {
/** Whether this specific node shows a checkbox */
checkable?: boolean;
/** Whether only this node's checkbox is disabled */
disableCheckbox?: boolean;
}import React, { useState } from "react";
import Tree from "rc-tree";
const ConditionalCheckbox = () => {
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const treeData = [
{
key: '0-0',
title: 'Project Root (checkable)',
children: [
{
key: '0-0-0',
title: 'Source Files (checkable)',
children: [
{ key: '0-0-0-0', title: 'main.js' },
{ key: '0-0-0-1', title: 'utils.js' },
],
},
{
key: '0-0-1',
title: 'Config (checkbox disabled)',
disableCheckbox: true,
children: [
{ key: '0-0-1-0', title: 'package.json', disableCheckbox: true },
],
},
{
key: '0-0-2',
title: 'Logs (not checkable)',
checkable: false,
children: [
{ key: '0-0-2-0', title: 'error.log', checkable: false },
],
},
],
},
];
return (
<Tree
prefixCls="rc-tree"
checkable
treeData={treeData}
checkedKeys={checkedKeys}
onCheck={(checked, info) => {
console.log('Conditional check:', checked);
const keys = Array.isArray(checked) ? checked : checked.checked;
setCheckedKeys(keys);
}}
defaultExpandAll
/>
);
};/**
* Detailed information provided in selection events
*/
interface SelectionEventInfo<TreeDataType extends BasicDataNode = DataNode> {
/** Event type */
event: 'select';
/** Whether the node was selected (true) or deselected (false) */
selected: boolean;
/** The node that was selected/deselected */
node: EventDataNode<TreeDataType>;
/** Array of all selected node data */
selectedNodes: TreeDataType[];
/** Native mouse event that triggered the selection */
nativeEvent: MouseEvent;
}/**
* Comprehensive checkbox event details
*/
interface CheckboxEventInfo<TreeDataType extends BasicDataNode = DataNode> {
/** Event type */
event: 'check';
/** The node that was checked/unchecked */
node: EventDataNode<TreeDataType>;
/** New checked state of the node */
checked: boolean;
/** Native mouse event */
nativeEvent: MouseEvent;
/** Array of all checked node data */
checkedNodes: TreeDataType[];
/** Array of checked nodes with their tree positions */
checkedNodesPositions?: { node: TreeDataType; pos: string }[];
/** Keys of nodes in half-checked (indeterminate) state */
halfCheckedKeys?: Key[];
}Install with Tessl CLI
npx tessl i tessl/npm-rc-tree