I'm building a web application that will show a hierarchy of things. The hierarchy will closely resemble that of a file system with folders and files, i.e. I'll have folders that contains files and subfolders in any depth level (though it will probably never go deeper than three levels).
The whole hierarchy will be shown in one view. It will be shown in a tree style and the folders can be expanded/closed by the user at will. The diffrent levels are indented, just as a standard file system browser.
What is a good way of representing this with HTML and CSS? Note that it is not the design/look itself I need help with but rather how to structure this in a good way using HTML. Should I use lists?
An approach framed using div
and span
, explained below with a working example at last.
Every folder contains 2 types of contents. Files
and inner Folders
. So a basic structure is designed with a overall container.
Overall Container:
<div id="hierarchy">
<!--folder structure goes here-->
</div>
Folder Structure:
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 1</span>
<span class="file fa-file-excel-o">File 11</span>
<span class="file fa-file-code-o">File 12</span>
<span class="file fa-file-pdf-o">File 13</span>
</div>
Folder Structure (with no files):
<div class="foldercontainer">
<span class="folder fa-folder">Folder 1</span>
<span class='noitems'>No Items</span>
</div>
The foldercontainer
contains span
elements that specifies the file names. First span
element contains the folder title, while the remaining contains the filenames. The data-
attribute isexpanded
specifies whether the specified folder is expanded or collapsed.
If a folder contains no files, then add the noitems
span
element to the structure.
While a folder contains another folder, just add the same html as a child to it. i.e.,
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 1</span>
<span class="file fa-file-excel-o">File 11</span>
<span class="file fa-file-code-o">File 12</span>
<span class="file fa-file-pdf-o">File 13</span>
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 1-1</span>
<span class="file fa-file-excel-o">File 1-11</span>
<span class="file fa-file-code-o">File 1-12</span>
<span class="file fa-file-pdf-o">File 1-13</span>
</div>
</div>
Javascript:
The click
event is delegated from the parent #hierarchy
element to the folders and files, to handle click in a single event listener. On clicking a folder, it is expanded and the icon changes. On clicking again it collapses and resets the icon.
While the inner folder is expanded and outer folder is collapsed, when expanding the outer folder, the inner folder contents states are preserved, by design.
Refer this nice article to learn how to handle events on multiple elements in a single listener.
Note: The code can be altered to make use of CSS custom variables and Data attributes access to CSS to be more efficient, while the former is not supported in IE and latter has its own disadvantages in cross-browser support. So use at your own risk.
Working example with various hierarchies:
var hierarchy = document.getElementById("hierarchy");
hierarchy.addEventListener("click", function(event){
var elem = event.target;
if(elem.tagName.toLowerCase() == "span" && elem !== event.currentTarget)
{
var type = elem.classList.contains("folder") ? "folder" : "file";
if(type=="file")
{
alert("File accessed");
}
if(type=="folder")
{
var isexpanded = elem.dataset.isexpanded=="true";
if(isexpanded)
{
elem.classList.remove("fa-folder-o");
elem.classList.add("fa-folder");
}
else
{
elem.classList.remove("fa-folder");
elem.classList.add("fa-folder-o");
}
elem.dataset.isexpanded = !isexpanded;
var toggleelems = [].slice.call(elem.parentElement.children);
var classnames = "file,foldercontainer,noitems".split(",");
toggleelems.forEach(function(element){
if(classnames.some(function(val){return element.classList.contains(val);}))
element.style.display = isexpanded ? "none":"block";
});
}
}
});
#hierarchy
{
font-family: FontAwesome;
width: 300px;
}
.foldercontainer, .file, .noitems
{
display: block;
padding: 5px 5px 5px 50px;
}
.folder
{
color: red;
}
.file
{
color: green;
}
.folder, .file
{
cursor: pointer;
}
.noitems
{
display: none;
pointer-events: none;
}
.folder:hover,.file:hover
{
background: yellow;
}
.folder:before, .file:before
{
padding-right: 10px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<div id="hierarchy">
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 1</span>
<span class="file fa-file-excel-o">File 11</span>
<span class="file fa-file-code-o">File 12</span>
<span class="file fa-file-pdf-o">File 13</span>
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 1-1</span>
<span class="file fa-file-excel-o">File 1-11</span>
<span class="file fa-file-code-o">File 1-12</span>
<span class="file fa-file-pdf-o">File 1-13</span>
</div>
<div class="foldercontainer">
<span class="folder fa-folder">Folder 1-2</span>
<span class='noitems'>No Items</span>
</div>
<div class="foldercontainer">
<span class="folder fa-folder">Folder 1-3</span>
<span class='noitems'>No Items</span>
</div>
<div class="foldercontainer">
<span class="folder fa-folder">Folder 1-4</span>
<span class='noitems'>No Items</span>
</div>
</div>
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 2</span>
<span class="file fa-file-excel-o">File 21</span>
<span class="file fa-file-code-o">File 22</span>
<span class="file fa-file-pdf-o">File 23</span>
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 2-1</span>
<span class="file fa-file-excel-o">File 2-11</span>
<span class="file fa-file-code-o">File 2-12</span>
<span class="file fa-file-pdf-o">File 2-13</span>
<div class="foldercontainer">
<span class="folder fa-folder">Folder 2-1-1</span>
<span class='noitems'>No Items</span>
</div>
</div>
</div>
<div class="foldercontainer">
<span class="folder fa-folder-o" data-isexpanded="true">Folder 3</span>
<span class="file fa-file-excel-o">File 31</span>
<span class="file fa-file-code-o">File 32</span>
<span class="file fa-file-pdf-o">File 33</span>
<div class="foldercontainer">
<span class="folder fa-folder">Folder 3-1</span>
<span class='noitems'>No Items</span>
</div>
</div>
</div>
The good way to represent it in HTML is to organize your file list as a... HTML list :) For example you might get this:
<ul>
<li>Folder 1
<ul>
<li>SubFile 1</li>
<li>SubFile 2</li>
<li>SubFile 3</li>
</ul></li>
<li>Folder 2
<ul>
<li>SubFile 4</li>
<li>SubFile 5</li>
<li>SubFile 6</li>
</ul></li>
<li>Main File 1</li>
<li>Main File 2</li>
</ul>
Then the CSS can be very soft, because the list already represents a hierarchy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With