SlickGrid has this functionality, see the tree demo.

If you want to build your own, here is an example (jsFiddle demo): Build your table with a data-depth attribute to indicate the depth of the item in the tree (the levelX CSS classes are just for styling indentation): 

<table id="mytable">
    <tr data-depth="0" class="collapse level0">
        <td><span class="toggle collapse"></span>Item 1</td>
        <td>123</td>
    </tr>
    <tr data-depth="1" class="collapse level1">
        <td><span class="toggle"></span>Item 2</td>
        <td>123</td>
    </tr>
</table>

Then when a toggle link is clicked, use Javascript to hide all <tr> elements until a <tr> of equal or less depth is found (excluding those already collapsed):

$(function() {
    $('#mytable').on('click', '.toggle', function () {
        //Gets all <tr>'s  of greater depth below element in the table
        var findChildren = function (tr) {
            var depth = tr.data('depth');
            return tr.nextUntil($('tr').filter(function () {
                return $(this).data('depth') <= depth;
            }));
        };

        var el = $(this);
        var tr = el.closest('tr'); //Get <tr> parent of toggle button
        var children = findChildren(tr);

        //Remove already collapsed nodes from children so that we don't
        //make them visible. 
        //(Confused? Remove this code and close Item 2, close Item 1 
        //then open Item 1 again, then you will understand)
        var subnodes = children.filter('.expand');
        subnodes.each(function () {
            var subnode = $(this);
            var subnodeChildren = findChildren(subnode);
            children = children.not(subnodeChildren);
        });

        //Change icon and hide/show children
        if (tr.hasClass('collapse')) {
            tr.removeClass('collapse').addClass('expand');
            children.hide();
        } else {
            tr.removeClass('expand').addClass('collapse');
            children.show();
        }
        return children;
    });
});
Answer from bcoughlan on Stack Overflow
🌐
W3Schools
w3schools.com › howto › howto_js_treeview.asp
How To Create a Tree View
Well organized and easy to understand Web building tutorials with lots of examples of how to use HTML, CSS, JavaScript, SQL, Python, PHP, Bootstrap, Java, XML and more.
🌐
Webix
webix.com › widget › treetable
JavaScript TreeTable UI Widget – HTML5 Tree Table and TreeGrid I Webix
JavaScript / HTML5 TreeTable UI control widget with data export, current state saving for jQuery or Angular project. Bootstrap Web TreeGrid component for Tree Table front-end functionality.
Top answer
1 of 6
45

SlickGrid has this functionality, see the tree demo.

If you want to build your own, here is an example (jsFiddle demo): Build your table with a data-depth attribute to indicate the depth of the item in the tree (the levelX CSS classes are just for styling indentation): 

<table id="mytable">
    <tr data-depth="0" class="collapse level0">
        <td><span class="toggle collapse"></span>Item 1</td>
        <td>123</td>
    </tr>
    <tr data-depth="1" class="collapse level1">
        <td><span class="toggle"></span>Item 2</td>
        <td>123</td>
    </tr>
</table>

Then when a toggle link is clicked, use Javascript to hide all <tr> elements until a <tr> of equal or less depth is found (excluding those already collapsed):

$(function() {
    $('#mytable').on('click', '.toggle', function () {
        //Gets all <tr>'s  of greater depth below element in the table
        var findChildren = function (tr) {
            var depth = tr.data('depth');
            return tr.nextUntil($('tr').filter(function () {
                return $(this).data('depth') <= depth;
            }));
        };

        var el = $(this);
        var tr = el.closest('tr'); //Get <tr> parent of toggle button
        var children = findChildren(tr);

        //Remove already collapsed nodes from children so that we don't
        //make them visible. 
        //(Confused? Remove this code and close Item 2, close Item 1 
        //then open Item 1 again, then you will understand)
        var subnodes = children.filter('.expand');
        subnodes.each(function () {
            var subnode = $(this);
            var subnodeChildren = findChildren(subnode);
            children = children.not(subnodeChildren);
        });

        //Change icon and hide/show children
        if (tr.hasClass('collapse')) {
            tr.removeClass('collapse').addClass('expand');
            children.hide();
        } else {
            tr.removeClass('expand').addClass('collapse');
            children.show();
        }
        return children;
    });
});
2 of 6
40

In modern browsers, you need only very little to code to create a collapsible tree :

var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for(var i = 0; i < tree.length; i++){
    tree[i].addEventListener('click', function(e) {
        var parent = e.target.parentElement;
        var classList = parent.classList;
        if(classList.contains("open")) {
            classList.remove('open');
            var opensubs = parent.querySelectorAll(':scope .open');
            for(var i = 0; i < opensubs.length; i++){
                opensubs[i].classList.remove('open');
            }
        } else {
            classList.add('open');
        }
        e.preventDefault();
    });
}
body {
    font-family: Arial;
}

ul.tree li {
    list-style-type: none;
    position: relative;
}

ul.tree li ul {
    display: none;
}

ul.tree li.open > ul {
    display: block;
}

ul.tree li a {
    color: black;
    text-decoration: none;
}

ul.tree li a:before {
    height: 1em;
    padding:0 .1em;
    font-size: .8em;
    display: block;
    position: absolute;
    left: -1.3em;
    top: .2em;
}

ul.tree li > a:not(:last-child):before {
    content: '+';
}

ul.tree li.open > a:not(:last-child):before {
    content: '-';
}
<ul class="tree">
  <li><a href="#">Part 1</a>
    <ul>
      <li><a href="#">Item A</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item B</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item C</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item D</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item E</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
    </ul>
  </li>

  <li><a href="#">Part 2</a>
    <ul>
      <li><a href="#">Item A</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item B</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item C</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item D</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item E</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
    </ul>
  </li>

  <li><a href="#">Part 3</a>
    <ul>
      <li><a href="#">Item A</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item B</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item C</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item D</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item E</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

(see also this Fiddle)

🌐
jQuery Script
jqueryscript.net › blog › best-tree-table.html
10 Best Tree Table Plugins In JavaScript (2026 Update) | jQuery Script
November 25, 2020 - A simple tree table plugin with jQuery to create a tree structure in your HTML table that enables you to collapse & expand nested table rows with minus and plus buttons.
🌐
jQuery Script
jqueryscript.net › jquery plugins › jquery table plugins
Create Tree Structure In HTML Table - simple-tree-table | Free jQuery Plugins
A simple tree table plugin with jQuery to create a tree structure in your HTML table that enables you to collapse & expand nested table rows with minus and plus buttons.
🌐
Reddit
reddit.com › r/html › how to create a tree table in pure html?
r/HTML on Reddit: How to create a tree table in pure HTML?
April 27, 2024 -

I want to be able to render tree tables in Markdown documents. The sole method of achieving this appears to be by using HTML+ES6+CSS. That's too much for most processors. However, HTML is widely accepted.

I thought to request assistance at Stack Overflow. However, as you might have estimated, based upon me asking here, it was not well received.

Consequently, I didn't consider this to be possible, until I recently located https://gitlab.com/gitlab-org/gitlab/-/issues/21506#note_262038275, which appeared to demonstrate that it might be. Despite that, although I've been unable to reliably introduce nesting of more than one level using pure HTML:

<table>
	<thead>
		<tr>
			<th>1</th>
			<th>2</th>
			<th>3</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<ol>
					<li>
						ph1
						</td>
							<td>That</td>
							<td>Hip Hip</td>
							</tr>
							<tr>
						<td>
					</li>
					<ol>
						<li>
							ph1.ph1
							</td>
								<td>That</td>
								<td>Hip Hip</td>
								</tr>
								<tr>
							<td>
						</li>
						<li>
							ph2.ph2
							</td>
								<td>That</td>
								<td>Hip Hip</td>
								</tr>
								<tr>
							<td>
						</li>
					</ol>
					<li>ph3
						<td>
							Attention
						</td>
					</li>
				</ol>
			</td>
		</tr>
		<tr>
			<td>
				<ol>
					<li>
						ph1
						</td>
							<td>That</td>
							<td>Hip Hip</td>
							</tr>
							<tr>
						<td>
					</li>
					<ol>
						<li>
							ph1.ph1
							</td>
								<td>That</td>
								<td>Hip Hip</td>
								</tr>
								<tr>
							<td>
						</li>
						<li>
							ph2.ph2
							</td>
								<td>That</td>
								<td>Hip Hip</td>
								</tr>
								<tr>
							<td>
						</li>
					</ol>
					<li>ph3
						<td>
							Attention
						</td>
					</li>
				</ol>
			</td>
		</tr>
		<tr>
			<td>
				<ol>
					<li>
						ph1
						</td>
							<td>That</td>
							<td>Hip Hip</td>
							</tr>
							<tr>
						<td>
					</li>
					<ol>
						<li>
							ph1.ph1
							</td>
								<td>That</td>
								<td>Hip Hip</td>
								</tr>
								<tr>
							<td>
						</li>
						<li>
							ph2.ph2
							</td>
								<td>That</td>
								<td>Hip Hip</td>
								</tr>
								<tr>
							<td>
						</li>
					</ol>
					<li>ph3
						<td>
							Attention
						</td>
					</li>
				</ol>
			</td>
		</tr>
	</tbody>
</table>

Am I doing something incorrect, or might it be impossible?

Top answer
1 of 11
8

Use the semantically appropriate tag for lists: <ul>. simply nest them. you can hide part of the structure, or maybe create it on the fly.

<ul id='n0>
  <li id='n1'>One guy</li>
  <li id='n2'>Second guy
    <ul id='n2.0'>
      <li id='n2.1'>first one of second guy</li>
      <li id='n2.2'>last of second</li>
    </ul>
  </li>
  <li id='n3'>Third one</li>
</ul>

and so on. the naming of items is up to you, i usually do it either reflect the struture (as here), or the DB ids.

2 of 11
8

I don't have an answer, but I have an illustration for those who have trouble visualizing OP's need.

Unix QPS (visual process manager) in Tree View shows just such a tree/table.

Google image search finds a few sample images.

Personally, would love to know how to implement this in a browser.

Edit: Added a sample image:


(source: nada.kth.se)

Edit: Crude implementation

<!doctype html public "-//w3c//dtd xhtml 1.0 strict//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd">
<html>
    <head>
        <style>
            .removed
            {
                display:none;
            }

            .expands
            {
                cursor:pointer; cursor:hand;
            }

            .child1 td:first-child
            {
                padding-left: 1em;
            }

            .child2 td:first-child
            {
                padding-left: 2em;
            }
        </style>
        <script>
            function toggle()
            {
                for(var i=0; i<arguments.length; i++)
                {
                    with(document.getElementById(arguments[i]))
                    {
                        if(className.indexOf('removed') > -1)
                        {
                            className = className.replace('removed');
                        }
                        else
                        {
                            className += ' removed';
                        }
                    }
                }
            }
        </script>
    </head>
    <body>
    <table>
        <thead>
            <tr>
                <th>Person</th>
                <th>Prop 1</th>
                <th>Prop 2</th>
                <th>Prop 3</th>
            </tr>
        </thead>
        <tbody>
            <tr id="p1" class="expands" onclick="toggle('p2','p3')">
                <td>P1</td>
                <td>a</td>
                <td>b</td>
                <td>c</td>
            </tr>
            <tr id="p2" class="removed child1">
                <td>P2</td>
                <td>a</td>
                <td>b</td>
                <td>c</td>
            </tr>
            <tr id="p3" class="removed child2">
                <td>P3</td>
                <td>a</td>
                <td>b</td>
                <td>c</td>
            </tr>
        </tbody>
        <tfoot>
            <tr>
                <td>Totals:</td>
                <td>x</td>
                <td>y</td>
                <td>z</td>
            </tr>
        </tfoot>
    </table>
    </body>
</html>
🌐
Culmat
culmat.github.io › jsTreeTable
jsTreeTable
We cannot provide a description for this page right now
Find elsewhere
🌐
MDBootstrap
mdbootstrap.com › standard › treetable
Bootstrap Treetable - examples & tutorial
The Treetable component can render your data with a simple HTML. You simply create a HTML markup for your table nested within a div tag with a "treetable" class - you can customize your table later by adding data-mdb-attributes to the wrapper.
🌐
CSS Script
cssscript.com › home › tree table
Best Free tree table In JavaScript & CSS - CSS Script
Transform Bootstrap tables into expandable tree structures with BootstrapTreeTable. Supports unlimited hierarchy levels, search, and customizable styling. DemoDownload ... An accessible expandable HTML enhancement script that allows the user to toggle (expand/collapse) table rows just like ...
🌐
CodePen
codepen.io › st-iv › pen › YzPpPYG
Nested Table -Tree View
Minimize HTML Editor · Fold All · Unfold All · <h3>Nested Tables <small class="text-muted">with tree view-like connecting lines</small></h3> <br> <table class="table table-condensed"> <thead> <tr> <th></th> <th>Header</th> <th>Header</th> <th>Header</th> <th>Header</th> </tr> </thead> <tbody> <tr id="tr-detail" class="tr-detail hidden"> <td></td> <td colspan="4"> <div class="detail-content"> <ul> <li> <div class="detail"></div> <div class="detail detail-main"> <fieldset> <legend><span class="label label-primary">Nested Data</span></legend> <div> <table class="table table-condensed"> <thead>
🌐
Cubicphuse
ludo.cubicphuse.nl › jquery-treetable
jQuery treetable
jQuery treetable is a plugin for jQuery, the 'Write Less, Do More, JavaScript Library'. With this plugin you can display a tree in an HTML table, e.g. a directory structure or a nested list. Why not use a list, you say? Because lists are great for displaying a tree, and tables are not.
🌐
GeeksforGeeks
geeksforgeeks.org › javascript › create-a-table-of-content-in-tree-view-architecture-using-html-css-and-javascript
Create a Table of Content in Tree View Architecture using HTML, CSS and JavaScript - GeeksforGeeks
July 12, 2025 - This kind of view gives your website an organized look, to create a tree view architecture of a drop we can use HTML, CSS, and JavaScript. We will divide the whole procedure into two sections Creating structure and Designing structure. Below both sections are elaborated · Creating Structure: In this section, we will create a basic structure of a Table of Content in the Tree View Architecture of elements.
🌐
GitHub
gist.github.com › jonrimmer › 1291088
Creating Tree-Tables in HTML and CSS · GitHub
October 16, 2011 - Creating Tree-Tables in HTML and CSS. GitHub Gist: instantly share code, notes, and snippets.
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › API › Document_Object_Model › Building_and_updating_the_DOM_tree
Building and updating the DOM tree - Web APIs | MDN
October 20, 2025 - You can build this table and its internal child elements by using just a few DOM methods. Remember to keep in mind the tree model for the structures you are planning to create; this will make it easier to write the necessary code. In the <table> tree of Figure 1 the element <table> has one child: the element <tbody>. <tbody> has two children.
🌐
DHTMLX
dhtmlx.com › docs › products › dhtmlxTreeGrid
JavaScript TreeGrid (TreeTable) Control - HTML5 TreeGrid - DHTMLX TreeGrid
DHTMLX TreeGrid is a full-featured HTML5 tree table with drag and drop, filtering, sorting, and frozen columns ⌚ Evaluate all JavaScript TreeGrid features during a 30-day free trial!
🌐
GitHub
github.com › ludo › jquery-treetable
GitHub - ludo/jquery-treetable: jQuery plugin to show a tree structure in a table · GitHub
jQuery treetable is a plugin for jQuery, the 'Write Less, Do More, JavaScript Library'. With this plugin you can display a tree in an HTML table, e.g. a directory structure or a nested list.
Starred by 751 users
Forked by 270 users
Languages   HTML 84.2% | JavaScript 14.8% | CSS 1.0%
🌐
HackerNoon
hackernoon.com › top-5-javascript-treegrid-treetable-components-20f03f4b46c8
TOP 5 JavaScript TreeGrid (TreeTable) Components | HackerNoon
February 22, 2019 - JavaScript Tree component is a very popular and convenient control that helps create data-rich applications. A hierarchical approach to data organization provides many benefits to an end-user. You can find tree lists in applications of all kinds.
🌐
JQuery
plugins.jquery.com › treetable
jQuery treetable | The jQuery Plugin Registry
jQuery plugin for displaying a tree structure in a (HTML) table, i.e.