Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Representing folder hierarchy with html

Tags:

html

css

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?

like image 663
haagel Avatar asked Jul 10 '13 08:07

haagel


2 Answers

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>
like image 186
Vignesh Raja Avatar answered Oct 17 '22 20:10

Vignesh Raja


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.

like image 39
Maxime Lorant Avatar answered Oct 17 '22 18:10

Maxime Lorant