Skip to content
CanopyX

Tree grid

Expandable branches with lazy children, path search, filters that keep the tree's shape, detail rows and checkboxes.

CanopyTreeView113,550 nodes in 393 static filesDocumentation for the tree grid

8 demos

File explorer Open this demo full screen

Expandable branches with lazy children, path search, filters that keep the tree's shape, detail rows and checkboxes.

Build one like it

The smallest complete version, in each language CanopyX supports for this view. The demo above is the same API with more data.

using CanopyX;
using CanopyX.Html;

var files = new CanopyTreeView("files", "File shares") {
    Selection = CanopySelectionMode.Single,
    Search = new CanopySearchOptions()
};
files.Columns.Add(new CanopyColumn("name", "Name") {
    Sortable = true,
    Sizing = CanopyColumnSizing.Preferred(280)
});
files.Columns.Add(new CanopyColumn("size", "Size") {
    Kind = CanopyColumnKind.Number,
    Sortable = true
});
files.Columns.Add(new CanopyColumn("owner", "Owner") { Sortable = true });
files.Columns.Add(new CanopyColumn("modified", "Modified") {
    Kind = CanopyColumnKind.DateTime,
    Sortable = true
});

var finance = new CanopyNode("finance", @"\\fs01\finance") {
    Kind = "folder",
    Expanded = true
};
finance.Children.Add(
    Document("budget", "Budget 2026.xlsx", 482_304, "anna.kowalska", 14));
finance.Children.Add(
    Document("invoices", "Invoices Q3.pdf", 2_310_144, "ben.okafor", 9));
var payroll = Document("payroll", "Payroll export.csv", 96_256, "chen.wei", 2);
payroll.Badges.Add(new CanopyBadge("Shared externally", CanopyTone.Warning));
finance.Children.Add(payroll);

var people = new CanopyNode("people", @"\\fs01\people") {
    Kind = "folder",
    Expanded = true
};
people.Children.Add(
    Document("handbook", "Staff handbook.docx", 1_048_576, "dana.levi", 30));
people.Children.Add(
    Document("rota", "On-call rota.xlsx", 40_960, "erik.lund", 1));

files.Roots.Add(finance);
files.Roots.Add(people);
files.SaveHtmlPage("files.html");

CanopyNode Document(string id, string name, long bytes, string owner, int age) {
    var node = new CanopyNode(id, name) { Kind = "file" };
    node.Cells["size"] = new CanopyCell(bytes) { Text = $"{bytes / 1024} KB" };
    node.Cells["owner"] = owner;
    var saved = new DateTime(2026, 10, 16, 9, 30, 0, DateTimeKind.Utc);
    node.Cells["modified"] = saved.AddDays(-age);
    return node;
}

Run this snippet (tree grid, C#)Its output, generated with the site.

Try this in the demo

  1. Lazy branches

    Expand a share, then one of its departments.

    Each branch opens from one pack file in data/, read the first time you open it. The page never downloads the whole tree.

  2. Search shards

    Type budget into Search files and folders and pick a hit.

    Only the shards for the words you typed are read; the tree then opens every branch on the path to the hit.

  3. Filters

    Turn on Only changed in the last 7 days.

    Folders above a changed file stay visible, so the tree keeps its shape around the matches.

  4. Detail rows

    Expand a file that has an arrow, then its History and a version.

    The version's changes open as a before and after table inside the tree, under the file they belong to.

  5. Deep links

    Select a row and look at the address bar of the full-screen page.

    The hash carries the row's path. Opening that address expands straight to the row.

On disk/live/files/The explorer's own 393 files, 42.2 MB, explored with CanopyXOpen the file layout
Every file the bundle writer produced for the demo above, with its size and role. Open data/ and its packs to see why one branch costs a single small file.