CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-rc-tree

Tree UI component for React with selection, checkboxes, drag-drop, and virtual scrolling features

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

selection-checking.mddocs/

Selection & Checking

RC Tree provides comprehensive selection and checking functionality with support for single/multiple selection, checkbox hierarchies, and strict/non-strict checking modes.

Capabilities

Selection System

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;
}

Checkbox System

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:

Basic Selection

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>
  );
};

Multiple Selection

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
    />
  );
};

Basic Checkbox Tree

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
    />
  );
};

Strict Checking Mode

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
    />
  );
};

Custom Checkbox Rendering

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
    />
  );
};

Mixed Selection and Checking

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>
  );
};

Advanced Selection Features

Node-Level Selection Control

/**
 * Per-node selection configuration
 */
interface NodeSelectionConfig {
  /** Whether this specific node can be selected */
  selectable?: boolean;
  /** Whether this specific node is disabled */
  disabled?: boolean;
}

Custom Selection Logic

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
    />
  );
};

Advanced Checkbox Features

Node-Level Checkbox Control

/**
 * 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;
}

Conditional Checkbox Logic

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
    />
  );
};

Event Handling Details

Selection Event Information

/**
 * 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;
}

Checkbox Event Information

/**
 * 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

docs

async-loading.md

data-management.md

drag-drop.md

index.md

selection-checking.md

tree-component.md

tree-node.md

virtual-scrolling.md

tile.json