Interactive Tree Views with Lazy Loading - jQuery Radix Tree

File Size: 162 KB
Views Total: 51
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Interactive Tree Views with Lazy Loading - jQuery Radix Tree

Radix Tree is a feature-rich jQuery tree view plugin that transforms hierarchical data structures into interactive, accessible tree view components with advanced functionality like lazy loading, infinite scroll, and comprehensive keyboard navigation.

The plugin handles everything from simple nested lists to complex data explorers with thousands of nodes. It's ideal for dashboards, file browsers, and any interface requiring dynamic tree structures.

Features:

  • Deep Nesting: Unlimited tree depth for complex hierarchical data
  • Smart Checkboxes: Parent-child propagation with indeterminate states
  • Lazy Loading: Load children on demand with configurable delays
  • Infinite Scroll: Efficiently handle large datasets with pagination
  • Keyboard Navigation: Full arrow-key and space/enter accessibility
  • Badges & Tags: Visual indicators for node context and metadata
  • Custom Callbacks: Extensive event handling for expand, collapse, click, and check actions
  • Modern UI: SVG checkboxes with customizable CSS variables
  • Disabled States: Selective node disabling for better UX control

Keyboard Navigation

  • Arrow Up/Down: Navigate between nodes
  • Arrow Right: Expand focused node
  • Arrow Left: Collapse focused node
  • Space/Enter: Toggle checkbox or expand/collapse
  • Tab: Move focus into and out of tree

How to use it:

1. Include the required jQuery library (slim build) and plugin files:

<!-- jQuery is required -->
<script src="/path/to/cdn/jquery.slim.min.js"></script>

<!-- jQuery Radix Tree plugin -->
<link href="css/jquery-multiselect.css" rel="stylesheet" />
<script src="js/jquery-multiselect.js"></script>

2. Create an empty DIV container where the tree will be rendered.

<div class="radix-tree"></div>

3. Prepare your hierarchical data structure. Each node can have several properties:

  • label (string): The text displayed for the node.
  • children (array): An array of child node objects.
  • open (bool): Sets the node to be expanded by default.
  • checked (bool): The state of the node's checkbox.
  • lazy (bool): If true, children are loaded on demand via the lazyLoad callback.
  • badge (string|number): An optional badge.
  • tags (array): An array of strings for optional tags.
  • disabled (bool): Disables the node and its children.
  • infinite (bool): Enables infinite scroll for the node.
  • className (string): A custom CSS class for the node's <li> element.
const defaultData = [
  {
    label: 'Universe',
    open: true,
    checked: false,
    children: [
      {
        label: 'Galaxies',
        open: true,
        checked: false,
        children: [
          {
            label: 'Milky Way',
            open: false,
            checked: false,
          },
          {
            label: 'Andromeda',
            open: false,
            checked: false,
            lazy: true // Lazy load Andromeda star systems
          }
        ]
      },
      {
        label: 'Black Holes',
        open: false,
        checked: false,
        children: [
          { label: 'Supermassive', open: false, checked: false, lazy: true },
          { label: 'Stellar-mass', open: false, checked: false, lazy: true }
        ]
      },
      {
        label: 'Nebulae',
        open: false,
        checked: false,
        lazy: true // Lazy load nebulae
      }
    ]
  },
  {
    label: 'Multiverse',
    open: false,
    checked: false,
    children: [
      { label: 'Parallel Universe 1', checked: false, lazy: true },
      { label: 'Parallel Universe 2', open: false, checked: false, lazy: true }
    ]
  }
];

4. Initialize the tree with your data structure:

$('.radix-tree').radixTree({ 
  data: defaultData
});

5. For performance, you can load node children asynchronously. Set lazy: true on a node and provide a lazyLoad function during initialization. The function receives the node and a done callback.

function myLazyLoad(node, done) {
  // Fetch data from an API
  fetch(`/api/children?node=${node.label}`)
    .then(res => res.json())
    .then(children => { done(children);
    })
    .catch(err => {
      console.error("Lazy load failed", err);
      done([{ label: 'Error loading data' }]);
    });
}

$('.radix-tree').radixTree({
  data: [{ label: 'My Data', lazy: true }],
  lazyLoad: myLazyLoad,
});

6. For very large datasets, combine lazy: true and infinite: true. The lazyLoad callback receives additional opts with page information. You call done(children, hasMore) to signal if more pages are available.

function infiniteLazyLoad(node, done, opts) {
  const page = opts.page || 1;
  const pageSize = opts.pageSize || 20;
  // Fetch a page of data...
  const children = []; // Your fetched children
  const hasMore = true; // Did the API indicate more pages?
  done(children, hasMore);
}
$('.radix-tree').radixTree({
  data: largeData,
  lazyLoad: infiniteLazyLoad,
  pageSize: 5, 
});

7. All default configuration options:

  • data: An array of node objects that defines the structure and content of the tree.
  • lazyLoad: A callback function that fetches child nodes on demand for any node with lazy: true. It receives the parent node and a done function to pass the new children to.
  • lazyLoadDelay: A number in milliseconds that sets a global delay for all lazyLoad operations.
  • pageSize: A number that specifies how many items to load at a time when using infinite scroll or paginated lazy loading.
  • paginateThreshold: An optional number. Pagination UI (like a "Load More" button) will only appear if the pageSize is greater than or equal to this value.
$('.radix-tree').radixTree({
  data: defaultData,
  lazyLoadDelay: 1000, // ms, default delay for lazy loading
  pageSize: 20,        // default page size for infinite scroll/lazy load
  // paginateThreshold is now optional
  // Sample lazyLoad function for demo
  lazyLoad: function(node, done) {
    // Simulate async loading based on label
    setTimeout(function() {
      let children = [];
      switch (node.label) {
        case 'Planets':
          children = [
            { label: 'Mercury', checked: false },
            { label: 'Venus', checked: false },
            { label: 'Earth', open: false, checked: false, lazy: true },
            { label: 'Mars', checked: false },
            { label: 'Jupiter', checked: false },
            { label: 'Saturn', checked: false },
            { label: 'Uranus', checked: false },
            { label: 'Neptune', checked: false }
          ];
          break;
        case 'Asteroid Belt':
          children = [
            { label: 'Ceres', checked: false },
            { label: 'Vesta', checked: false },
            { label: 'Pallas', checked: false },
            { label: 'Hygiea', checked: false }
          ];
          break;
        case 'Alpha Centauri System':
          children = [
            { label: 'Alpha Centauri A', checked: false },
            { label: 'Alpha Centauri B', checked: false },
            { label: 'Proxima Centauri', checked: false }
          ];
          break;
        case 'Andromeda':
          children = [
            { label: 'Star System 1', checked: false },
            { label: 'Star System 2', checked: false }
          ];
          break;
        case 'Supermassive':
          children = [
            { label: 'Sagittarius A*', checked: false },
            { label: 'M87*', checked: false }
          ];
          break;
        case 'Stellar-mass':
          children = [
            { label: 'Cygnus X-1', checked: false },
            { label: 'V404 Cygni', checked: false }
          ];
          break;
        case 'Nebulae':
          children = [
            { label: 'Orion Nebula', checked: false },
            { label: 'Crab Nebula', checked: false },
            { label: 'Eagle Nebula', checked: false }
          ];
          break;
        case 'Earth':
          children = [
            { label: 'Moon', checked: false },
            { label: 'ISS', checked: false }
          ];
          break;
        case 'Parallel Universe 1':
          children = [
            { label: 'Alt Galaxy', checked: false, lazy: true }
          ];
          break;
        case 'Parallel Universe 2':
          children = [
            { label: 'Alt Galaxy', checked: false, lazy: true }
          ];
          break;
        case 'Alt Galaxy':
          children = [
            { label: 'Alt Solar System', checked: false, lazy: true }
          ];
          break;
        case 'Alt Solar System':
          children = [
            { label: 'Alt Earth', checked: false, lazy: true }
          ];
          break;
        case 'Alt Earth':
          children = [
            { label: 'Alt Moon', checked: false },
            { label: 'Alt Mars', checked: false }
          ];
          break;
        default:
          children = [
            { label: 'Loading complete', checked: false }
          ];
      }
      done(children);
    }, settings.lazyLoadDelay);
  }
});

8. Callback functions:

  • onExpand: A callback function that executes when a node is expanded.
  • onCollapse: A callback function that executes when a node is collapsed.
  • onClick: A callback function that executes when a user clicks on a node's label.
  • onCheck: A callback function that executes when a node's checkbox state changes.
$('.radix-tree').radixTree({
  data,
  onExpand: (node, detailsElem) => {
    console.log('Expanded:', node.label);
  },
  onCollapse: (node, detailsElem) => {
    console.log('Collapsed:', node.label);
  },
  onClick: (node, elem) => {
    alert('Clicked: ' + node.label);
  },
  onCheck: (node, checkboxElem) => {
    console.log('Checked:', node.label, checkboxElem.checked);
  }
});

9. API methods:

// Get all checked nodes
const checked = $('.radix-tree').radixTree('getChecked');

// Set checkbox state
$('.radix-tree').radixTree('setChecked', nodeId, true);

// Expand/collapse nodes
$('.radix-tree').radixTree('expand', nodeId);
$('.radix-tree').radixTree('collapse', nodeId);

// Data manipulation
const currentData = $('.radix-tree').radixTree('getData');
$('.radix-tree').radixTree('setData', newData);

10. Override the default CSS variables for theming:

:root {
  --width: 12;
  --rounding: 4px;
  --accent: #696;
  --dark-grey: #ddd;
  --grey: #eee;
  --light-grey: #f8f8f8;
  --checkbox-size: 1.2em;
  --checkbox-border: 2px solid #bbb;
  --checkbox-radius: 6px;
  --checkbox-shadow: 0 1px 2px rgba(0,0,0,0.07);
  --checkbox-checked-bg: #4caf50;
  --checkbox-checked-border: 2px solid #388e3c;
  --checkbox-indeterminate-bg: #ffc107;
  --checkbox-indeterminate-border: 2px solid #ffa000;
}

Changelog:

v1.0.2 (2025-06-28)


This awesome jQuery plugin is developed by dxmari. For more Advanced Usages, please check the demo page or visit the official website.