Creating a Recursive Tree Component in Vue.js

Alex Jover Morales

Recursion has been always a pain to learn in algorithmics. In some cases however, using recursion feels more natural than using iteration. Traversing a tree is one of them.

We can create recursive components in Vue.js and any other framework by following the same mechanics.

Creating a Tree Component

Imagine a component that must render a tree structure, for example showing a directory tree:

+ Root directory
  + Directory A
    + Directory A1
  + Directory B

We could represent a directory as a Tree, and all subdirectories as a list of Nodes for that tree. A tree has always a root node, which expands untill it reaches the leaf nodes.

For instance, we could use an object with the label and children keys for that:

const tree = {
  label: "A cool folder",
  children: [
    {
      label: "A cool sub-folder 1",
      children: [
        { label: "A cool sub-sub-folder 1" },
        { label: "A cool sub-sub-folder 2" }
      ]
    },
    { label: "This one is not that cool" }
  ]
}

Given the previous structure, let’s create a Tree.vue component that takes it as a prop and renders the root node:

Tree.vue

<template>
  <div class="tree">
    <ul class="tree-list">
      <node-tree :node="treeData"></node-tree>
    </ul>
  </div>
</template>

<script>
import NodeTree from "./NodeTree";

export default {
  props: {
    treeData: Object
  },
  components: {
    NodeTree
  }
};
</script>

<style>
.tree-list ul {
  padding-left: 16px;
  margin: 6px 0;
}
</style>

We’re adding some padding to the left of the lists, so they have that hierarchical look.

Nothing special happening here, we’re just getting a treeData property and passing it as the first node to a NodeTree component that we have yet to implement.

Implementing the Node Tree

A Node Tree must show its label, but at the same time it must render its children. In that way, a NodeTree is also a sub-tree.

A simple NodeTree.vue component would be:

NodeTree.vue

<template>
  <li class="node-tree">
    <span class="label">{{ node.label }}</span>
  </li>
</template>

<script>
export default {
  props: {
    node: Object
  }
};
</script>

But the component just shows a label, we still have to make it render its children, which are also tree nodes.

If you think about it, it’s the same case than recursive functions; they’re functions that call themselves as long as a condition is not fulfilled.

So, we have to make the node tree render a list of node trees. In order to access a component from the same component, we have to add the name component option:

NodeTree.vue

<template>
  <li class="node-tree">
    <span class="label">{{ node.label }}</span>

    <ul v-if="node.children && node.children.length">
      <node v-for="child in node.children" :node="child"></node>
    </ul>
  </li>
</template>

<script>
export default {
  name: "node",
  props: {
    node: Object
  }
};
</script>

That will make the NodeTree component call itself until it reaches the leaf node.

As you can see, we’re using name: "node" thus the <node> tag. The children tree nodes are only rendered when there are children, passing the child node as their property.

Using the Tree Component

In order to try it out, for instance, you can create an App.vue component passing the previous data structure to the Tree component:

App.vue

<template>
  <div>
    <tree :tree-data="tree"></tree>
  </div>
</template>

<script>
import Tree from "./Tree";

export default {
  data: () => ({
    tree: {
      label: "A cool folder",
      children: [
        {
          label: "A cool sub-folder 1",
          children: [
            { label: "A cool sub-sub-folder 1" },
            { label: "A cool sub-sub-folder 2" }
          ]
        },
        { label: "This one is not that cool" }
      ]
    }
  }),
  components: {
    Tree
  }
};
</script>

Wrapping Up

Recursion doesn’t have to be hard, and Vue.js makes it a breeze by giving support from its DSL or template.

I hope that this article will help you build awesome Tree components!

Stay cool 🦄

  Tweet It

🕵 Search Results

🔎 Searching...