HTML TreeView component

Is it possible to build a TreeView GUI component with a plain HTML & CSS without using any Javascipt/GUI libraries ?

Answer is YES ! For that you just need a bunch of nested unordered html lists and some css tricks.

For the start we need some styles :

<style>
ul, .tree {
  list-style-type: none;
}
.tree {
  margin: 0;
  padding: 0;
}
.caret {
  cursor: pointer;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.caret::before {
  content: "[+]";
  color: black;
  display: inline-block;
  margin-right: 6px;
}
.caret-down::before {
  content: "[−]";
}
.nested {
  display: none;
}
.active {
  display: block;
}
</style>

Now let's build a PHP function which generates tree nodes by processing a given folder. That is,- our tree will be a file & directory structure of a given folder :

function generateNodes(&$node) {

  foreach ($node as $path => &$child) {
    if (!preg_match('#\.$#', $path)) {
      $files = scandir($path);
      if ($files !== false) {
        foreach ($files as $name) {
          if (!preg_match('#\.$#', $name))
            $child[$path.'/'.$name] = [];
        }
        uksort($child, function ($a, $b) {return is_dir($a) < is_dir($b);});
        generateNodes($child);
      }
    }
  }

}

Then we need a PHP function which given a complete generated tree structure as nested php arrays - generates nested unordered lists. That is,- transforms nested arrays into nested <UL> html tags :

function emitTree($nodes) {
  if (!$nodes) {
    return;
  }

  $added = false;
  foreach ($nodes as $k => $v) {
    preg_match('#\/[^\/]+$#', $k, $short);
    if ($v) {
      echo "<li><span class='caret'>{$short[0]}</span>";
      echo "<ul class='nested'>";
      emitTree($v);
      echo "</ul>";
      echo "</li>";
    }
    else {
        echo "<li><span style='background-color:#F8F9F9; border-radius:3px; border-style:solid; border-width:1px;'>{$short[0]}</span></li>";
    }
  }
}

In this way storage of tree in-memory is de-coupled from a representation of it in HTML, which will let you to choose a different tree loading mechanisms from a disk / database, etc.

Now, we just need to call our written PHP procedures in-order :

echo '<ul class="tree">';
$tree = ['/opt' => []];
generateNodes($tree);
emitTree($tree);
echo '</ul><br>';

Last final step is to emit to the client Javascript code which takes care of changing tree node styles in case of tree expansion/collapse - by attaching to node click events :

<script>
function toggler() {
  var toggler = document.getElementsByClassName("caret");
  var i;

  for (i = 0; i < toggler.length; i++) {
    toggler[i].addEventListener("click", function() {
      this.parentElement.querySelector(".nested").classList.toggle("active");
      this.classList.toggle("caret-down");
    });
  }

}
toggler();
</script>

That's it. If you followed everything exactly, when running example, you should get a view of /opt folder structure :

dirlist.png

BTW, terminal nodes (nodes without any child) are colored in gray. Happy TreeNoding :-)

No Comments Yet