CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jstree

jQuery tree plugin for creating interactive tree components with drag & drop, inline editing, checkboxes, search, and customizable node types

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

plugins.mddocs/

Additional Plugins

State management, node types, sorting, context menus, and other specialized functionality. These plugins extend jsTree's core capabilities with additional features for enhanced tree management and user interaction.

Capabilities

State Plugin

Persistent state management for preserving tree state across sessions.

/**
 * State plugin configuration
 */
interface StateConfig {
  /** Storage key for state data (default: "jstree") */
  key?: string;
  /** Events that trigger state save (default: ["changed.jstree", "open_node.jstree", "close_node.jstree"]) */
  events?: Array<string>;
  /** Time to live for state data in seconds (default: 3600) */
  ttl?: number;
  /** Custom filter function to determine what to save */
  filter?: function;
  /** Preserve loaded state on refresh (default: false) */
  preserve_loaded?: boolean;
}

/**
 * Save current tree state to storage
 */
save_state(): void;

/**
 * Restore tree state from storage
 */
restore_state(): void;

/**
 * Get current tree state object
 * @returns State object containing selected nodes, opened nodes, etc.
 */
get_state(): object;

/**
 * Set tree state from object
 * @param state - State object to restore
 * @param callback - Function to call when state is restored
 */
set_state(state: object, callback?: function): void;

/**
 * Clear saved state from storage
 */
clear_state(): void;

Usage Examples:

// Initialize with state plugin
$("#tree").jstree({
  "plugins": ["state"],
  "state": {
    "key": "my-tree-state",
    "events": ["changed.jstree", "open_node.jstree", "close_node.jstree"],
    "ttl": 7200, // 2 hours
    "filter": function(state) {
      // Only save certain parts of state
      return {
        core: {
          selected: state.core.selected,
          open: state.core.open
        }
      };
    }
  }
});

// Manual state operations
const tree = $("#tree").jstree(true);

// Save current state
tree.save_state();

// Get state object
const currentState = tree.get_state();
console.log("Current state:", currentState);

// Restore specific state
tree.set_state({
  core: {
    selected: ["node_1", "node_2"],
    open: ["parent_1", "parent_2"]
  }
});

// Clear saved state
tree.clear_state();

Types Plugin

Node type system with type-specific icons, behavior, and validation.

/**
 * Types plugin configuration
 */
interface TypesConfig {
  /** Default node type (default: "default") */
  default?: string;
  /** Type definitions */
  types?: {[type: string]: TypeDefinition};
}

interface TypeDefinition {
  /** Maximum number of children (default: -1 for unlimited) */
  max_children?: number;
  /** Maximum depth for this type (default: -1 for unlimited) */
  max_depth?: number;
  /** Valid children types (default: -1 for all types) */
  valid_children?: Array<string>|number;
  /** Icon class or URL for this type */
  icon?: string|boolean;
  /** Additional node attributes */
  li_attr?: object;
  /** Additional anchor attributes */
  a_attr?: object;
}

/**
 * Get node type
 * @param obj - Node to get type for
 * @returns Node type string
 */
get_type(obj: string|object): string;

/**
 * Set node type
 * @param obj - Node to set type for
 * @param type - New type name
 * @returns True on success
 */
set_type(obj: string|object, type: string): boolean;

Usage Examples:

// Initialize with types
$("#tree").jstree({
  "plugins": ["types"],
  "types": {
    "default": {
      "icon": "fa fa-file"
    },
    "folder": {
      "icon": "fa fa-folder",
      "valid_children": ["folder", "file"],
      "max_children": 50
    },
    "file": {
      "icon": "fa fa-file-o",
      "valid_children": [],
      "max_children": 0
    },
    "image": {
      "icon": "fa fa-image",
      "valid_children": [],
      "li_attr": {"class": "image-node"}
    }
  },
  "core": {
    "data": [
      {"text": "Documents", "type": "folder", "children": [
        {"text": "report.pdf", "type": "file"},
        {"text": "photo.jpg", "type": "image"}
      ]}
    ]
  }
});

// Type operations
const tree = $("#tree").jstree(true);

// Get node type
const nodeType = tree.get_type("node_1");
console.log("Node type:", nodeType);

// Set node type
tree.set_type("node_1", "folder");

// Create typed nodes
tree.create_node("#", {
  "text": "New Folder",
  "type": "folder"
});

Sort Plugin

Automatic and manual sorting of tree nodes.

/**
 * Sort plugin configuration
 */
interface SortConfig {
  /** Custom sort function */
  sort?: function;
  /** Case sensitive sorting (default: false) */
  case_sensitive?: boolean;
  /** Natural sorting (handles numbers correctly) */
  natural?: boolean;
}

/**
 * Sort nodes alphabetically
 * @param obj - Node to sort children of (default: root)
 * @param deep - Also sort all descendants (default: false)
 */
sort(obj?: string|object, deep?: boolean): void;

Usage Examples:

// Initialize with sorting
$("#tree").jstree({
  "plugins": ["sort"],
  "sort": {
    "case_sensitive": false,
    "natural": true,
    "sort": function(a, b) {
      // Custom sort logic
      const nodeA = this.get_node(a);
      const nodeB = this.get_node(b);
      
      // Sort folders before files
      if (nodeA.type === "folder" && nodeB.type !== "folder") return -1;
      if (nodeA.type !== "folder" && nodeB.type === "folder") return 1;
      
      // Then sort alphabetically
      return nodeA.text.toLowerCase().localeCompare(nodeB.text.toLowerCase());
    }
  }
});

// Manual sorting
const tree = $("#tree").jstree(true);
tree.sort(); // Sort root level
tree.sort("folder_1", true); // Sort folder and all descendants

Context Menu Plugin

Customizable right-click context menus with conditional items.

/**
 * Context menu plugin configuration
 */
interface ContextMenuConfig {
  /** Select node when showing context menu (default: true) */
  select_node?: boolean;
  /** Show menu at node position vs cursor position (default: true) */
  show_at_node?: boolean;
  /** Menu items configuration */
  items?: object|function;
}

interface ContextMenuItem {
  /** Display label */
  label?: string;
  /** Icon class */
  icon?: string;
  /** Action function */
  action?: function;
  /** Submenu items */
  submenu?: {[key: string]: ContextMenuItem};
  /** Separator */
  separator_before?: boolean;
  separator_after?: boolean;
  /** Conditional visibility */
  visible?: boolean|function;
  /** Conditional enablement */
  disabled?: boolean|function;
  /** Custom class name */
  _class?: string;
}

/**
 * Show context menu programmatically
 * @param obj - Node to show menu for
 * @param x - X coordinate (optional)
 * @param y - Y coordinate (optional)
 * @param e - Original event (optional)
 */
show_contextmenu(obj: string|object, x?: number, y?: number, e?: Event): void;

Usage Examples:

// Initialize with context menu
$("#tree").jstree({
  "plugins": ["contextmenu"],
  "contextmenu": {
    "items": function(node) {
      return {
        "create": {
          "label": "Create",
          "icon": "fa fa-plus",
          "action": function(data) {
            const inst = $.jstree.reference(data.reference);
            const obj = inst.get_node(data.reference);
            inst.create_node(obj, {}, "last", function(new_node) {
              setTimeout(function() { inst.edit(new_node); }, 0);
            });
          }
        },
        "rename": {
          "label": "Rename",
          "icon": "fa fa-edit",
          "action": function(data) {
            const inst = $.jstree.reference(data.reference);
            const obj = inst.get_node(data.reference);
            inst.edit(obj);
          }
        },
        "delete": {
          "label": "Delete",
          "icon": "fa fa-trash",
          "separator_before": true,
          "action": function(data) {
            const inst = $.jstree.reference(data.reference);
            const obj = inst.get_node(data.reference);
            if (inst.is_selected(obj)) {
              inst.delete_node(inst.get_selected());
            } else {
              inst.delete_node(obj);
            }
          }
        },
        "properties": {
          "label": "Properties",
          "icon": "fa fa-info",
          "separator_before": true,
          "visible": function(key, opt) {
            // Only show for certain node types
            return node.type === "file";
          },
          "action": function(data) {
            showNodeProperties(data.reference);
          }
        }
      };
    }
  }
});

// Dynamic context menu
$("#tree").jstree({
  "plugins": ["contextmenu", "types"],
  "contextmenu": {
    "items": function(node) {
      const items = {};
      
      // Add type-specific items
      if (node.type === "folder") {
        items.create_folder = {
          "label": "New Folder",
          "action": function(data) {
            // Create folder logic
          }
        };
        items.create_file = {
          "label": "New File", 
          "action": function(data) {
            // Create file logic
          }
        };
      }
      
      // Add common items
      items.rename = {
        "label": "Rename",
        "action": function(data) {
          const inst = $.jstree.reference(data.reference);
          inst.edit(data.reference);
        }
      };
      
      return items;
    }
  }
});

Unique Plugin

Ensures unique node names within parent nodes.

/**
 * Unique plugin configuration
 */
interface UniqueConfig {
  /** Case sensitive uniqueness check (default: false) */
  case_sensitive?: boolean;
  /** Trim whitespace when checking (default: true) */
  trim_whitespace?: boolean;
  /** Custom duplicate callback */
  duplicate?: function;
}

Usage Examples:

// Initialize with unique names
$("#tree").jstree({
  "plugins": ["unique"],
  "unique": {
    "case_sensitive": false,
    "duplicate": function(name, counter) {
      // Custom naming for duplicates
      return name + " (" + counter + ")";
    }
  }
});

// Automatic duplicate handling
const tree = $("#tree").jstree(true);
tree.create_node("#", {"text": "New Item"}); // Creates "New Item"
tree.create_node("#", {"text": "New Item"}); // Creates "New Item (2)"
tree.create_node("#", {"text": "new item"}); // Creates "new item (3)" if case_sensitive: false

Wholerow Plugin

Extends clickable area to full row width for easier interaction.

/**
 * Wholerow plugin configuration
 */
interface WholerowConfig {
  /** Enable wholerow selection */
  wholerow?: boolean;
}

Usage Examples:

// Initialize with wholerow
$("#tree").jstree({
  "plugins": ["wholerow"],
  "wholerow": {
    "wholerow": true
  }
});

// The entire row becomes clickable, not just the text/icon

Changed Plugin

Tracks and reports changes to the tree structure.

/**
 * Get array of changed node IDs since last call
 * @param callback - Function to call with changed nodes
 * @returns Array of changed node IDs
 */
get_changed(callback?: function): Array<string>;

Usage Examples:

// Initialize with changed tracking
$("#tree").jstree({
  "plugins": ["changed"]
});

// Get changed nodes
const tree = $("#tree").jstree(true);
const changedNodes = tree.get_changed();
console.log("Changed nodes:", changedNodes);

// Listen for changes
$("#tree").on("changed.jstree", function(e, data) {
  console.log("Tree changed:", data.changed);
});

Conditionalselect Plugin

Allows conditional node selection via callback functions.

/**
 * Conditionalselect plugin configuration
 */
interface ConditionalselectConfig {
  /** Function to determine if node can be selected */
  conditionalselect?: function;
}

type ConditionalSelectFunction = (node: object, event: Event) => boolean;

Usage Examples:

// Initialize with conditional selection
$("#tree").jstree({
  "plugins": ["conditionalselect"],
  "conditionalselect": {
    "conditionalselect": function(node, event) {
      // Only allow selection of leaf nodes
      return this.is_leaf(node);
    }
  }
});

// More complex conditions
$("#tree").jstree({
  "plugins": ["conditionalselect", "types"],
  "conditionalselect": {
    "conditionalselect": function(node, event) {
      // Prevent selection based on node type and user permissions
      if (node.type === "readonly") return false;
      if (node.li_attr && node.li_attr["data-locked"] === "true") return false;
      
      // Check user permissions
      const userRole = getCurrentUserRole();
      if (userRole === "viewer" && node.type === "admin") return false;
      
      return true;
    }
  }
});

Massload Plugin

Enables loading multiple nodes in a single request for performance optimization.

/**
 * Massload plugin configuration
 */
interface MassloadConfig {
  /** URL for mass loading endpoint */
  url?: string;
  /** Request data configuration */
  data?: function;
}

Usage Examples:

// Initialize with mass loading
$("#tree").jstree({
  "plugins": ["massload"],
  "massload": {
    "url": "/api/nodes/massload",
    "data": function(nodes) {
      return {
        "ids": nodes.join(","),
        "timestamp": Date.now()
      };
    }
  }
});

// Server endpoint should return data for multiple nodes at once
// instead of making individual requests for each node

Plugin Integration Patterns

Multi-Plugin Usage

Common patterns for combining multiple plugins effectively.

/**
 * Comprehensive tree setup with multiple plugins
 */
interface ComprehensiveTreeConfig {
  plugins: Array<string>;
  core: CoreConfig;
  checkbox?: CheckboxConfig;
  contextmenu?: ContextMenuConfig;
  dnd?: DnDConfig;
  search?: SearchConfig;
  state?: StateConfig;
  types?: TypesConfig;
  sort?: SortConfig;
  unique?: UniqueConfig;
  wholerow?: WholerowConfig;
  conditionalselect?: ConditionalselectConfig;
}

Usage Examples:

// Full-featured tree setup
$("#tree").jstree({
  "plugins": [
    "checkbox", "contextmenu", "dnd", "search", 
    "state", "types", "sort", "unique", "wholerow"
  ],
  "core": {
    "check_callback": true,
    "themes": {"stripes": true}
  },
  "checkbox": {
    "three_state": true,
    "cascade": "up+down+undetermined"
  },
  "contextmenu": {
    "items": contextMenuBuilder
  },
  "dnd": {
    "check_while_dragging": true,
    "drag_selection": true
  },
  "search": {
    "fuzzy": true,
    "show_only_matches": true
  },
  "state": {
    "key": "full-tree-state"
  },
  "types": {
    "folder": {"icon": "fa fa-folder"},
    "file": {"icon": "fa fa-file"}
  },
  "sort": {
    "case_sensitive": false
  }
});

// Event coordination across plugins
$("#tree").on("ready.jstree", function() {
  // Tree is fully initialized with all plugins
  const tree = $(this).jstree(true);
  
  // Restore state
  tree.restore_state();
  
  // Enable search UI
  $("#search-input").on("keyup", function() {
    tree.search($(this).val());
  });
});

Types

// Plugin-enhanced node object
interface EnhancedTreeNode extends TreeNode {
  // State plugin
  state?: {
    loaded?: boolean;
    opened?: boolean;
    selected?: boolean;
    disabled?: boolean;
  };
  
  // Types plugin
  type?: string;
  
  // Checkbox plugin (when enabled)
  state?: {
    checked?: boolean;
    undetermined?: boolean;
    checkbox_disabled?: boolean;
  };
  
  // Plugin-specific data
  data?: {
    [key: string]: any;
  };
}

// Combined plugin settings
interface PluginSettings {
  [plugin: string]: any;
}

docs

checkbox.md

configuration.md

contextmenu.md

core.md

dnd.md

events.md

index.md

plugins.md

search.md

tile.json