You have a SharePoint list or a documents library in which you management the content by managed metadata; you want to display the content of this list in accordance with a selected path chosen by the users. Natively, without additional feature to the site or list, you can use:

  1. The column header, directly from the list view
  1. With the new experience, the filter panel

However, you have no native Web Part that allows you to display a custom path selector.

Ok, but what for? Image you wish provide a documentation about tools in accordance with a use case. The users follow the path of use case and at the end, they should find all documents in accordance with them path. Like that:

Once the Term is retrieved, it is possible to display the result in accordance with this one.

Below, the solution I have chosen:

Get Taxonomy

PnPjs 🌳 to retrieve a Term Sets of current site based on a field from list:

sp.web.lists.getById('00000000-0000-0000-0000-000000000000').fields.getById('11111111-1111-1111-1111-111111111111').get().then((field) => {
    taxonomy.getDefaultSiteCollectionTermStore().getTermSetById(field.TermSetId).terms.get().then((t) => {
      console.log(t); /* HERE ALL TERMS FROM TERM SETS */

The result is 😅🙄:

Transfom data

Now, transform this result to an object that can be reused to display a tree. I chose the structure proposed by the framework jsTree.

First, create a function that allows to get each individual term:

public buildTree(ts: Array<any>): Array<any> {
    var tree = [];
    ts.forEach(term => {
        tree = this.branch(tree, term)
    return tree;

buildTree() use the most important recursive function named branch() that allows to reproduce the hierarchy:

private branch(tree: Array<any>, term: any, node: any = null, i: number = 0): Array<any> {
    var pathOfTerm = term.PathOfTerm.split(';');
    /* Switch level */
    var c = node == null ? tree : node;
    if (i < pathOfTerm.length) { /* Ensure not loop recursive */
        var r = c.find(function (obj) { return obj.text === pathOfTerm[i]; }); /* check if node already exist */
        if (r) { /* If exist */
            if ((i + 1) == pathOfTerm.length) { /* Update ID if node == current term */
       = term.Id.replace('/Guid(', '').replace(')/', '');
            } else { /* recursive children */
                this.branch(tree, term, r.children, i + 1);
        } else { /* Not exists, create new node */
            /* See : for all specification */
            var o = { "text": pathOfTerm[i], "id": null, "state": { "opened": false }, "children": [] };
            if ((i + 1) == pathOfTerm.length) { /* If it's a root node or last child, set ID */
       = term.Id.replace('/Guid(', '').replace(')/', '');
            } else { /* recursive children */
                this.branch(tree, term, o.children, i + 1);
    return c;

In this function, the following rows allow to define the template of each node :

var o = { "text": pathOfTerm[i], "id": null, "state": { "opened": false }, "children": [] }; = term.Id.replace('/Guid(', '').replace(')/', '');

And here the result of the object model 💪🏻 :

With this kind of data object, you can directly use the jsTree render or create your own  HTML structure like that :

Get the selected (clicked) Term

Now, you probably want get which term was selected, update the view and do something else...

To do this, add an `addEventListener()` on your render tree nodes (in my case, I'm using the CSS class `termSelector`) and attach the click event to the following function that return the object node selected :

public toggleSelectedTerm(tree: any, id: string): any {
    var n = tree.find(function (obj) { return === id; });
    if (!n) {
        tree.forEach(e => {
            if (!n && e.children.length > 0) {
                n = this.toggleSelectedTerm(e.children, id);
    if (n && !n.edited) {
        n.state.opened = !n.state.opened;
        /* Add flag for avoid overwrite recursivity */
        n.edited = true;
    return n;
Just be care that the event is bind only once.

If you use this function :

var selectedNode = this.toggleSelectedTerm([buidTree return], [ID of selected term]);

don't forget to reset the flag added by the previous function

delete n.edited;

Next Step

Display the content of list or documents library in accordance with the selected term.