JSFiddle - React, Tailwind, and code Playground

by Stephen Dunne

HTML

<div id="tree" tabindex="1">
        <ul>
            <li>
                <div>
                    <span class="c-treeview-actionButton"></span><span class="c-checkbox"></span><span
                        class="c-treeview-nodeText">Sample Tree View</span>
                </div>
                <ul>
                    <li>
                        <div>
                            <span class="c-treeview-actionButton"></span><span class="c-checkbox"></span><span
                                class="c-treeview-nodeText">Node 1</span>
                        </div>
                        <ul>
                        </ul>
                    </li>
                    <li>
                        <div>
                            <span class="c-treeview-actionButton"></span><span class="c-checkbox"></span><span
                                class="c-treeview-nodeText">Node 2</span>
                        </div>
                        <ul>
                        </ul>
                    </li>
                    <li>
                        <div>
                            <span class="c-treeview-actionButton"></span><span class="c-checkbox"></span><span
                                class="c-treeview-nodeText">Node 3</span>
                        </div>
                        <ul>
                            <li>
                                <div>
                                    <span class="c-treeview-actionButton"></span><span class="c-checkbox"></span><span
                                        class="c-treeview-nodeText">Node 3.1</span>
                                </div>
                                <ul>
                                </ul>
                            </li>
                            <li>
                                <div>
                                    <span class="c-treeview-actionButton"></span><span class="c-checkbox"></span><span
                                       ...

CSS

ul { padding-left: 20px; border: 0px dashed black;list-style: none; }
        
        .treeView { list-style: none; width: 250px; margin: 15px; /*float: left; display: inline-block;*/ }
        .treeViewNode { min-height: 20px; padding: 2px; }
        .treeViewNodeBody { display: inline-block; }
        .selectedNode { background-color: silver; }
        .focusedNode { border: 1px dashed blue; }
        .c-treeview-actionButton { cursor: pointer; }
        .c-treeview-nodeText { cursor: default; }
        .c-checkbox { border: 1px solid silver; cursor: pointer; width: 16px; height: 16px; }
        
        .ui-icon { float: left; }
        .ui-icon-plus { background-position: -16px -128px; }
        .ui-icon-plusthick { background-position: -32px -128px; }
        .ui-icon-minus { background-position: -48px -128px; }
        .ui-icon-minusthick { background-position: -64px -128px; }
        .ui-icon-x { background-position: -80px -128px; }
        .ui-icon-xthick { background-position: -96px -128px; }
        .ui-icon-check { background-position: -64px -144px; }
        .ui-icon-indeterminate { background-position: -80px -144px; }
        .ui-icon-none { background-position: -160px -144px; }

JavaScript

$(function () {

    var Cmb = Cmb || {};
    Cmb.UI = Cmb.UI || {};
    Cmb.UI.Enum = Cmb.UI.Enum || {};
    Cmb.UI.Enum.TreeView = Cmb.UI.Enum.TreeView || {};

    /*
            This defines a hashtable of functions that determines how specific key press events are
            handled by the tree view
            */
    Cmb.UI.Enum.TreeView.KeyEventHandler = {
        13: function (node) { // return
            if (node.options.selected) {
                node.toggleExpansion();
            } else {
                node.selectNode();
            }
        },
        32: function (node) { // space
            node.toggleCheckBoxState();
        },
        37: function (node) { // left
            if (node.options.canExpand && node.options.expanded) {
                node.toggleExpansion();
            } else {
                node.parent.focusNode();
            }
        },
        38: function (node) { // up
            var nodes = (node.parent || node).element.find(":cmb-treeviewnode:visible");
            var index = nodes.index(node.element);
            if (index === 0) { //first in visible list so focus on the parent if one exists
                (node.parent || node).focusNode();
            }
            if (index > 0) {
                $(nodes[index - 1]).treeViewNode("focusNode");
            }
        },
        39: function (node) { // right
            if (node.options.canExpand) {
                if (!node.options.expanded) {
                    node.toggleExpansion();
                } else {
                    $(node.options.childNodes[0]).treeViewNode("focusNode");
                }
            } else {
                var nodes = (node.parent || node).element.find(":cmb-treeviewnode:visible");
                var index = nodes.index(node.element);
                if (index < (nodes.length - 1)) {
                    $(nodes[index + 1]).treeViewNode("focusNode");
                }
            }
        },
        40: function (node) { //...