Use Case

To Show Records in Hierarchy/Tree view using Visualforce

Components Used

  1. Visualforce Page
  2. Apex Controller
  3. jQuery
  4. Bootstrap

Visualforce Page, Apex Controller works fine if you copy & Paste as given

Visualforce Logic

So Logic behind displaying hierarchy view was achieved simply using <ul> & <li> elements

So if you want a view of Account => Contacts =>Cases,

    <li> // first li
        <!-- place your content here for first node/level -->
            <li> // second li
                <!-- place your content here for Second node/level -->
                    <li> // third li
                        <!-- place your content here for Second node/level -->
                        <!-- So on repeat <ul> & <li> to dig into more level-->
                    </li> // end of third li
            </li> // end second li
    </li> // end first li

NOTE: you can use this with repeat/dataTable tags eithers, example explainded below

Visualforce Page (Actual)

<apex:page controller="GetAccountContacts" showHeader="false" sidebar="false">
    <!-- Mobile View -->
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <!-- jQuery CDN Reference -->
    <script src=""></script>
    <!-- Bootstarp css & Combined Css -->
    <link href="//" rel="stylesheet" />
    <link href="//" rel="stylesheet" />
        .tree {
            min-height: 20px;
            padding: 19px;
            margin-bottom: 20px;
            background-color: #fbfbfb;
            border: 1px solid #999;
            -webkit-border-radius: 4px;
            -moz-border-radius: 4px;
            border-radius: 4px;
            -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
            -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
            box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05)
        .tree li {
            list-style-type: none;
            margin: 0;
            padding: 10px 5px 0 5px;
            position: relative;
        .tree li::before,
        .tree li::after {
            content: '';
            left: -20px;
            position: absolute;
            right: auto;
        .tree li::before {
            border-left: 1px solid #999;
            bottom: 50px;
            height: 100%;
            top: 0;
            width: 1px;
        .tree li::after {
            border-top: 1px solid #999;
            height: 20px;
            top: 25px;
            width: 25px;
        .tree li span {
            -moz-border-radius: 5px;
            -webkit-border-radius: 5px;
            border: 1px solid #999;
            border-radius: 5px;
            display: inline-block;
            padding: 3px 8px;
            text-decoration: none;
        .tree li.parent_li>span {
            cursor: pointer !important;
        .tree>ul>li::after {
            border: 0;
        .tree li:last-child::before {
            height: 30px;
        .tree li.parent_li>span:hover,
        .tree li.parent_li>span:hover+ul li span {
            background: #eee;
            border: 1px solid #94a0b4;
            color: #000;
    <div class="tree well">
        <apex:repeat value="{!AccConCases}" var="a">
                    <span><i class="icon-folder-open icon-plus-sign"></i>Account</span> <a href="/{a.Id}"  target="_blank">{!a.Name}</a>
                        <apex:repeat value="{!a.Contacts}" var="c">
                                <span><i class="glyphicon glyphicon-user"></i> Contact</span><a href="/{!c.Id}"  target="_blank"></a> {!c.Name}
                                    <apex:repeat value="{!a.Cases}" var="ca">
                                            <span><i class="glyphicon glyphicon-briefcase"></i> Case</span><a href="/{!ca.Id}" target="_blank"></a> {!ca.CaseNumber}
    $(function() {
        $('.tree li:has(ul)').addClass('parent_li').find(' > span').attr('title', 'Collapse this branch');
        $('.tree li:has(ul)').addClass('parent_li').find(' > ul > li').hide('slow');
        $('.tree li.parent_li > span').on('click', function(e) {
            var children = $(this).parent('li.parent_li').find(' > ul > li');
            if (":visible")) {
                $(this).attr('title', 'Expand this branch').find(' > i').addClass('icon-plus-sign').removeClass('icon-minus-sign');
            } else {
                $(this).attr('title', 'Collapse this branch').find(' > i').addClass('icon-minus-sign').removeClass('icon-plus-sign');


public class GetAccountContacts {        
    public List<Account> getAccConCases(){
        return [select id, Name, (select id, Name from Account.Contacts), (select id, ContactId, CaseNumber from Cases) from account LIMIT 10];

Sample Output

Youtube Demo Link