JavaScript/jQuery TreeView - Getting Started
jQuery
Angular
Vue
React
The TreeView component displays a tree of text nodes from a local or remote source.
This tutorial shows how to create and configure the TreeView. The demo below shows the resulting UI:
Refer to the following sections for information on each configuration step. You can also find the full code in the GitHub repository.
Create a TreeView
jQuery
Add DevExtreme to your jQuery application and use the following code to create a TreeView:
$(function() { $("#treeView").dxTreeView({ // Configuration goes here }); });
<!DOCTYPE html> <html> <head> <!-- ... --> <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css"> <link rel="stylesheet" href="index.css"> <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/24.2.3/js/dx.all.js"></script> <script type="text/javascript" src="index.js"></script> </head> <body class="dx-viewport"> <div id="treeView"></div> </body> </html>
#treeView { width: 300px; }
Angular
Add DevExtreme to your Angular application and use the following code to create a TreeView:
<dx-tree-view id="treeView" <!-- Configuration goes here --> > </dx-tree-view>
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTreeViewModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTreeViewModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { }
#treeView { width: 300px; }
Vue
Add DevExtreme to your Vue application and use the following code to create a TreeView:
<template> <DxTreeView id="treeView" <!-- Configuration goes here --> > </DxTreeView> </template> <script> import 'devextreme/dist/css/dx.light.css'; import { DxTreeView } from 'devextreme-vue/tree-view'; export default { components: { DxTreeView } } </script> <style> #treeView { width: 300px; } </style>
React
Add DevExtreme to your React application and use the following code to create a TreeView:
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import { TreeView } from 'devextreme-react/tree-view'; function App() { return ( <TreeView id="treeView" {/* Configuration goes here */} /> ); } export default App;
#treeView { width: 300px; }
Bind the TreeView to Data
To bind the TreeView to a local array, use the dataSource property. Refer to the articles listed below for instructions on how to do this for other storage types:
The TreeView supports plain and hierarchical data structures. To use plain data, set the dataStructure property to "plain". In this case, each data object should contain the id, text, and parentId fields. If objects use custom field names, use the keyExpr, displayExpr, and parentIdExpr properties to specify them:
jQuery
$(function() { $("#treeView").dxTreeView({ // ... dataSource: products, dataStructure: "plain", keyExpr: "ID", displayExpr: "name", parentIdExpr: "categoryId", }); });
const IMAGE_URL = "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/products/"; const products = [ { ID: "1", name: "Stores" }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West" }, { ID: "1_1_1", categoryId: "1_1", name: "Video Players" }, { ID: "1_1_1_1", categoryId: "1_1_1", name: "HD Video Player", image: IMAGE_URL + "1.png", price: 220 }, { ID: "1_1_1_2", categoryId: "1_1_1", name: "SuperHD Video Player", image: IMAGE_URL + "2.png", price: 270 }, { ID: "1_1_2", categoryId: "1_1", name: "Televisions" }, { ID: "1_1_2_1", categoryId: "1_1_2", name: "SuperLCD 42", image: IMAGE_URL + "7.png", price: 1200 }, { ID: "1_1_2_2", categoryId: "1_1_2", name: "SuperLED 42", image: IMAGE_URL + "5.png", price: 1450 }, { ID: "1_1_2_3", categoryId: "1_1_2", name: "SuperLED 50", image: IMAGE_URL + "4.png", price: 1600 }, { ID: "1_1_2_4", categoryId: "1_1_2", name: "SuperLCD 55", image: IMAGE_URL + "6.png", price: 1750 }, { ID: "1_1_2_5", categoryId: "1_1_2", name: "SuperLCD 70", image: IMAGE_URL + "9.png", price: 4000 }, { ID: "1_1_3", categoryId: "1_1", name: "Monitors" }, { ID: "1_1_3_1", categoryId: "1_1_3", name: "19\"", }, { ID: "1_1_3_1_1", categoryId: "1_1_3_1", name: "DesktopLCD 19", image: IMAGE_URL + "10.png", price: 160 }, { ID: "1_1_4", categoryId: "1_1", name: "Projectors" }, { ID: "1_1_4_1", categoryId: "1_1_4", name: "Projector Plus", image: IMAGE_URL + "14.png", price: 550 }, { ID: "1_1_4_2", categoryId: "1_1_4", name: "Projector PlusHD", image: IMAGE_URL + "15.png", price: 750 } ];
Angular
<dx-tree-view ... [dataSource]="products" dataStructure="plain" keyExpr="ID" displayExpr="name" parentIdExpr="categoryId"> </dx-tree-view>
import { Component } from '@angular/core'; import { Product, ProductsService } from './products.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { products: Product[]; constructor(service: ProductsService) { this.products = service.getProducts(); } }
import { Injectable } from '@angular/core'; export class Product { ID: string; name: string; categoryId?: string; image?: string; price?: number; } const IMAGE_URL = "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/products/"; const products: Product[] = [ { ID: "1", name: "Stores" }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West" }, { ID: "1_1_1", categoryId: "1_1", name: "Video Players" }, { ID: "1_1_1_1", categoryId: "1_1_1", name: "HD Video Player", image: IMAGE_URL + "1.png", price: 220 }, { ID: "1_1_1_2", categoryId: "1_1_1", name: "SuperHD Video Player", image: IMAGE_URL + "2.png", price: 270 }, { ID: "1_1_2", categoryId: "1_1", name: "Televisions" }, { ID: "1_1_2_1", categoryId: "1_1_2", name: "SuperLCD 42", image: IMAGE_URL + "7.png", price: 1200 }, { ID: "1_1_2_2", categoryId: "1_1_2", name: "SuperLED 42", image: IMAGE_URL + "5.png", price: 1450 }, { ID: "1_1_2_3", categoryId: "1_1_2", name: "SuperLED 50", image: IMAGE_URL + "4.png", price: 1600 }, { ID: "1_1_2_4", categoryId: "1_1_2", name: "SuperLCD 55", image: IMAGE_URL + "6.png", price: 1750 }, { ID: "1_1_2_5", categoryId: "1_1_2", name: "SuperLCD 70", image: IMAGE_URL + "9.png", price: 4000 }, { ID: "1_1_3", categoryId: "1_1", name: "Monitors" }, { ID: "1_1_3_1", categoryId: "1_1_3", name: "19\"", }, { ID: "1_1_3_1_1", categoryId: "1_1_3_1", name: "DesktopLCD 19", image: IMAGE_URL + "10.png", price: 160 }, { ID: "1_1_4", categoryId: "1_1", name: "Projectors" }, { ID: "1_1_4_1", categoryId: "1_1_4", name: "Projector Plus", image: IMAGE_URL + "14.png", price: 550 }, { ID: "1_1_4_2", categoryId: "1_1_4", name: "Projector PlusHD", image: IMAGE_URL + "15.png", price: 750 } ]; @Injectable({ providedIn: 'root' }) export class ProductsService { getProducts(): Product[] { return products; } }
Vue
<template> <DxTreeView ... :data-source="products" data-structure="plain" key-expr="ID" display-expr="name" parent-id-expr="categoryId" > </DxTreeView> </template> <script> // ... import products from './products'; export default { // ... data() { return { products: products, } }, } </script>
const IMAGE_URL = "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/products/"; const products = [{ ID: "1", name: "Stores" }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West" }, { ID: "1_1_1", categoryId: "1_1", name: "Video Players" }, { ID: "1_1_1_1", categoryId: "1_1_1", name: "HD Video Player", image: IMAGE_URL + "1.png", price: 220 }, { ID: "1_1_1_2", categoryId: "1_1_1", name: "SuperHD Video Player", image: IMAGE_URL + "2.png", price: 270 }, { ID: "1_1_2", categoryId: "1_1", name: "Televisions" }, { ID: "1_1_2_1", categoryId: "1_1_2", name: "SuperLCD 42", image: IMAGE_URL + "7.png", price: 1200 }, { ID: "1_1_2_2", categoryId: "1_1_2", name: "SuperLED 42", image: IMAGE_URL + "5.png", price: 1450 }, { ID: "1_1_2_3", categoryId: "1_1_2", name: "SuperLED 50", image: IMAGE_URL + "4.png", price: 1600 }, { ID: "1_1_2_4", categoryId: "1_1_2", name: "SuperLCD 55", image: IMAGE_URL + "6.png", price: 1750 }, { ID: "1_1_2_5", categoryId: "1_1_2", name: "SuperLCD 70", image: IMAGE_URL + "9.png", price: 4000 }, { ID: "1_1_3", categoryId: "1_1", name: "Monitors" }, { ID: "1_1_3_1", categoryId: "1_1_3", name: "19\"", }, { ID: "1_1_3_1_1", categoryId: "1_1_3_1", name: "DesktopLCD 19", image: IMAGE_URL + "10.png", price: 160 }, { ID: "1_1_4", categoryId: "1_1", name: "Projectors" }, { ID: "1_1_4_1", categoryId: "1_1_4", name: "Projector Plus", image: IMAGE_URL + "14.png", price: 550 }, { ID: "1_1_4_2", categoryId: "1_1_4", name: "Projector PlusHD", image: IMAGE_URL + "15.png", price: 750 }]; export default products;
React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeView from 'devextreme-react/tree-view'; import products from './products'; function App() { return ( <TreeView ... dataSource={products} dataStructure="plain" keyExpr="ID" displayExpr="name" parentIdExpr="categoryId" /> ); } export default App;
const IMAGE_URL = "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/products/"; const products = [ { ID: "1", name: "Stores" }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West" }, { ID: "1_1_1", categoryId: "1_1", name: "Video Players" }, { ID: "1_1_1_1", categoryId: "1_1_1", name: "HD Video Player", image: IMAGE_URL + "1.png", price: 220 }, { ID: "1_1_1_2", categoryId: "1_1_1", name: "SuperHD Video Player", image: IMAGE_URL + "2.png", price: 270 }, { ID: "1_1_2", categoryId: "1_1", name: "Televisions" }, { ID: "1_1_2_1", categoryId: "1_1_2", name: "SuperLCD 42", image: IMAGE_URL + "7.png", price: 1200 }, { ID: "1_1_2_2", categoryId: "1_1_2", name: "SuperLED 42", image: IMAGE_URL + "5.png", price: 1450 }, { ID: "1_1_2_3", categoryId: "1_1_2", name: "SuperLED 50", image: IMAGE_URL + "4.png", price: 1600 }, { ID: "1_1_2_4", categoryId: "1_1_2", name: "SuperLCD 55", image: IMAGE_URL + "6.png", price: 1750 }, { ID: "1_1_2_5", categoryId: "1_1_2", name: "SuperLCD 70", image: IMAGE_URL + "9.png", price: 4000 }, { ID: "1_1_3", categoryId: "1_1", name: "Monitors" }, { ID: "1_1_3_1", categoryId: "1_1_3", name: "19\"", }, { ID: "1_1_3_1_1", categoryId: "1_1_3_1", name: "DesktopLCD 19", image: IMAGE_URL + "10.png", price: 160 }, { ID: "1_1_4", categoryId: "1_1", name: "Projectors" }, { ID: "1_1_4_1", categoryId: "1_1_4", name: "Projector Plus", image: IMAGE_URL + "14.png", price: 550 }, { ID: "1_1_4_2", categoryId: "1_1_4", name: "Projector PlusHD", image: IMAGE_URL + "15.png", price: 750 } ]; export default products;
If your dataset has a hierarchical structure, refer to the following demo for details: Hierarchical Data Structure.
Customize Node Appearance
Use the itemTemplate property to specify a template for all nodes as shown in this tutorial. If you want to add a template for a specific node, use the template node's property. This setting overrides the global template.
You can also use additional fields to customize node appearance. For example, you can enable the expanded field for those nodes that should be expanded on startup:
jQuery
$(function(){ $("#treeView").dxTreeView({ // ... itemTemplate: function(item) { if (item.price) { return `<div> ${item.name} ($${item.price}) </div>`; } else { return `<div> ${item.name} </div>`; } }, }); });
// ... const products = [ { ID: "1", name: "Stores", expanded: true }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West", expanded: true }, // ... { ID: "1_1_2", categoryId: "1_1", name: "Televisions", expanded: true }, // ... ];
Angular
<dx-tree-view ... itemTemplate="productTemplate"> <div *dxTemplate="let product of 'productTemplate'"> {{ product.price ? product.name + " $(" + product.price + ")" : product.name }} </div> </dx-tree-view>
// ... export class Product { ID: string; name: string; categoryId?: string; expanded?: boolean; image?: string; price?: number; } const products: Product[] = [ { ID: "1", name: "Stores", expanded: true }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West", expanded: true }, // ... { ID: "1_1_2", categoryId: "1_1", name: "Televisions", expanded: true }, // ... ]; // ...
Vue
<template> <DxTreeView ... item-template="product-template"> <template #product-template="product"> {{ product.data.price ? product.data.name + " ($" + product.data.price + ")" : product.data.name }} </template> </DxTreeView> </template> // ...
// ... const products = [ { ID: "1", name: "Stores", expanded: true }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West", expanded: true }, // ... { ID: "1_1_2", categoryId: "1_1", name: "Televisions", expanded: true }, // ... ]; export default products;
React
// ... const itemTemplate = (item) => { if (item.price) { return `${item.name} ($${item.price})`; } else { return `${item.name}`; } } function App() { return ( <TreeView ... itemRender={itemTemplate} /> ); } export default App;
// ... const products = [ { ID: "1", name: "Stores", expanded: true }, { ID: "1_1", categoryId: "1", name: "Super Mart of the West", expanded: true }, // ... { ID: "1_1_2", categoryId: "1_1", name: "Televisions", expanded: true }, // ... ]; export default products;
Search Data
The TreeView can display a search bar that allows users to search nodes. Enable the searchEnabled property to add the search bar. Use the searchMode property to specify whether nodes should contain (default), start with, or match the search string. In this tutorial, search results include only nodes that start with the search string:
jQuery
$(function(){ $("#treeView").dxTreeView({ // ... searchEnabled: true, searchMode: "startswith" }); });
Angular
<dx-tree-view ... [searchEnabled]="true" searchMode="startswith"> <!-- ... --> </dx-tree-view>
Vue
<template> <DxTreeView ... :search-enabled="true" search-mode="startswith"> <!-- ... --> </DxTreeView> </template> // ...
React
// ... function App() { return ( <TreeView ... searchEnabled={true} searchMode="startswith" /> ); } export default App;
Select Nodes
To configure node selection, use the following properties:
selectByClick
Enables selection by a click.showCheckBoxesMode
Adds checkboxes if you set this property to "normal" or "selectAll". The latter mode additionally displays the "Select All" checkbox at the top of the TreeView.selectionMode
Sets the selection mode to "single" or "multiple" (default).onItemSelectionChanged
Specifies a function that is executed when a single node is selected or deselected.
In this tutorial, we enable selection by a click and use the single-node selection mode. Also, we specify the onItemSelectionChanged function to display the selected product, its picture, and price.
jQuery
$(function(){ $("#treeView").dxTreeView({ // ... selectionMode: "single", selectByClick: true, onItemSelectionChanged: function(e) { const selectedProduct = e.itemData; if(selectedProduct.price) { $("#product-details").removeClass("hidden"); $("#product-details > img").attr("src", selectedProduct.image); $("#product-details > .price").text("$" + selectedProduct.price); $("#product-details > .name").text(selectedProduct.name); } else { $("#product-details").addClass("hidden"); } } }); });
<!DOCTYPE html> <html> <head> <!-- ... --> </head> <body class="dx-viewport"> <div id="treeView"></div> <div id="product-details" class="hidden"> <img src="" /> <div class="name"></div> <div class="price"></div> </div> </body> </html>
#treeView, #product-details { display: inline-block; width: 300px; } #product-details { vertical-align: top; width: 400px; height: 420px; margin-left: 20px; } #product-details > img { border: none; height: 300px; width: 400px; } #product-details > .name { text-align: center; font-size: 20px; } #product-details > .price { text-align: center; font-size: 24px; } .hidden { visibility: hidden; }
Angular
<dx-tree-view ... selectionMode="single" [selectByClick]="true" (onItemSelectionChanged)="selectProduct($event)"> <div *dxTemplate="let product of 'productTemplate'"> {{ product.price ? product.name + "(" + product.price + ")" : product.name }} </div> </dx-tree-view> <div id="product-details" *ngIf="currentProduct.price"> <img [src]="currentProduct.image" /> <div class="name">{{currentProduct.name}}</div> <div class="price">${{ currentProduct.price }}</div> </div>
// ... export class AppComponent { // ... currentProduct: Product; constructor(service: ProductsService) { // ... this.currentProduct = this.products[0]; } selectProduct(e) { this.currentProduct = e.itemData; } }
#treeView, #product-details { display: inline-block; width: 300px; } #product-details { vertical-align: top; width: 400px; height: 420px; margin-left: 20px; } #product-details > img { border: none; height: 300px; width: 400px; } #product-details > .name { text-align: center; font-size: 20px; } #product-details > .price { text-align: center; font-size: 24px; }
Vue
<template> <div> <DxTreeView ... selection-mode="single" :select-by-click="true" @item-selection-changed="selectProduct"> <!-- ... --> </DxTreeView> <div id="product-details" v-if="currentProduct.price"> <img :src="currentProduct.image" > <div class="name">{{ currentProduct.name }}</div> <div class="price">${{ currentProduct.price }}</div> </div> </div> </template> <script> import DxTreeView from 'devextreme-vue/tree-view'; import products from './products'; export default { components: { DxTreeView }, data() { return { // ... currentProduct: products[0], } }, methods: { selectProduct(e) { this.currentProduct = e.itemData; } } } </script> <style> #treeView, #product-details { display: inline-block; width: 300px; } #product-details { vertical-align: top; width: 400px; height: 420px; margin-left: 20px; } #product-details > img { border: none; height: 300px; width: 400px; } #product-details > .name { text-align: center; font-size: 20px; } #product-details > .price { text-align: center; font-size: 24px; } </style>
React
// ... function App() { const [selectedNode, setSelectedNode] = useState(products[0]); const selectProduct = (e) => { setSelectedNode(e.itemData); } // ... return ( <div> <TreeView ... selectionMode="single" selectByClick={true} onItemSelectionChanged={selectProduct} /> { selectedNode.price && <div id="product-details"> <img src={selectedNode.image}/> <div className="name">{selectedNode.name}</div> <div className="price">{`$${ selectedNode.price}`}</div> </div> } </div> ); } export default App;
#treeView, #product-details { display: inline-block; width: 300px; margin: 10px; } #product-details { vertical-align: top; width: 400px; height: 420px; margin-left: 20px; } #product-details > img { border: none; height: 300px; width: 400px; } #product-details > .name { text-align: center; font-size: 20px; } #product-details > .price { text-align: center; font-size: 24px; }
Enable Node Drag & Drop
Users can drag and drop nodes to rearrange them and change the data hierarchy. This functionality is not used in this tutorial. For more information, refer to the following demos: Drag & Drop for Plain Data Structure and Drag & Drop for Hierarchical Data Structure.
Enhance Performance on Large Datasets
If the TreeView is bound to a large dataset, the component can load data and render nodes on demand as a user expands them. This functionality is not demonstrated in this tutorial because it uses only a small dataset. You can refer to the following demos for information on how to load data on demand: Virtual Mode and Load Data on Demand.
For further information on the TreeView component, refer to the following resources: