Creating a Tree Component using Svelte.js
Jun 5, 2021
I was playing around with Svelte.js recently and was curious to know how easy it
would be to build a Tree component using it. It was simpler than I expected it to be
with Svelte’s recursive svelte:self
feature. Let me explain how its
done.
So the idea is to have two components. One named Tree
and the other one named
Node
. Under the hood, we will be using ul
and li
tags, where ul
will
wrap the entire tree and each li
tag within it will be a node. Yes, we are
going to render the tree as a flat list of li
tags.
Before that let’s design the data model of the tree which has to be passed as a props to the component. Following is the type of the data.
type Node = {
data: string,
expanded: boolean,
children?: Node[]
}
It is a recursive type and data fitting in the above type will look like,
let treeData = {
data: 'Root',
expanded: false,
children: [
{
data: 'Child 1',
expanded: false,
children: [{ data: 'Grand Child 1' }]
},
{
data: 'Child 2',
expanded: false,
children: [{ data: 'Grand Child 2' }]
},
{data: 'Child 3'}
]
}
Now the Tree
component is just a wrapper around the root Node
component.
<!-- Tree.svelte -->
<script>
import Node from "./Node.svelte";
export let data; // type Node
</script>
<ul>
<Node node={data} />
</ul>
<style>
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
</style>
Now we are reaching the important part, where we are going to render the nodes
in a recursive component using svelte:self
.
<!-- Node.svelte -->
<script>
import { slide } from 'svelte/transition';
import ClosedIcon from './ClosedIcon.svelte';
import OpenedIcon from './OpenedIcon.svelte';
export let node;
export let level = 0;
function toggle() {
node.expanded = !node.expanded;
}
</script>
<li on:click={toggle} style="padding-left:{level*1}rem" transition:slide>
{#if !node.expanded }
<ClosedIcon/>
{:else}
<OpenedIcon/>
{/if}
{node.data}
</li>
{#if node.expanded && node.children}
{#each node.children as child}
<svelte:self node={child} level={level+1}/>
{/each}
{/if}
<style>
li {
border-bottom: solid 1px #eee;
margin: 0 0;
padding: 1rem;
background: #fafafa;
display: flex;
}
</style>
We are rendering the node data in a <li>
tag and if the list is expanded,
we are recursively rendering all the children of the node right below it.
Note that we have level
prop and we increase it at each level. This will be
used to indent the node, so that it appears like a tree.
Svelte’s built in slide
transition makes it super easy to add some nice
transition so that it gives a visual feedback when expanding or collapsing.
You can check this component in this Svelte REPL link.