
Syncfusion Blazor Dropdown Tree
- 231 installs
- 4 repo stars
- Updated July 28, 2026
- syncfusion/blazor-ui-components-skills
Use syncfusion-blazor-dropdown-tree for development tasks
About
syncfusion-blazor-dropdown-tree: A skill for development. This provides functionality for development workflows.
- syncfusion-blazor-dropdown-tree
Syncfusion Blazor Dropdown Tree by the numbers
- 231 all-time installs (skills.sh)
- +13 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,658 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/blazor-ui-components-skills --skill syncfusion-blazor-dropdown-treeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 231 |
|---|---|
| repo stars | ★ 4 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/blazor-ui-components-skills ↗ |
What it does
Use syncfusion-blazor-dropdown-tree for development tasks
Files
Implementing Syncfusion Blazor Dropdown Tree Component
The Blazor Dropdown Tree component is a hierarchical data selection control that displays tree-structured data in a dropdown popup. It supports local and remote data binding, single and multi-selection modes, checkboxes, filtering, custom templates, and comprehensive event handling.
When to Use This Skill
- Display hierarchical data in a compact dropdown format
- Single selection: Allow users to select one item from a tree structure (default mode)
- Multi-selection: Enable selection of multiple tree nodes using CTRL+SHIFT shortcuts
- Checkbox selection: Provide checkbox-based multi-selection with dependent state management
- Filter tree data: Implement search functionality to filter nodes by text
- Remote data sources: Bind to OData, OData V4, Web API, or custom service endpoints
- Custom templates: Personalize item display, selected value display, and popup header
- Handle events: Respond to lifecycle events, selection changes, popup actions
- Form validation: Integrate with form validation frameworks
- Styling and appearance: Apply CSS classes, disabled states, and theme customization
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation and NuGet package setup
- Web and Server app configuration
- Basic component initialization
- Data binding fundamentals
- First working example
Selection and Modes
📄 Read: references/selection-and-modes.md
- Single selection (default behavior)
- Multi-selection with AllowMultiSelection property
- Keyboard shortcuts (CTRL, SHIFT)
- Preselected values and dynamic selection
- Getting selected values with @bind-Value
- Clearing selection
Checkbox Features
📄 Read: references/checkbox-features.md
- ShowCheckBox property for multi-item selection
- AutoUpdateCheckState for dependent parent-child relationships
- ShowSelectAll for selecting/deselecting all nodes
- SelectAllAsync and programmatic selection methods
Data Binding and Remote Data
📄 Read: references/data-binding-operations.md
- Local data binding (hierarchical and self-referential)
- ExpandoObject and DynamicObject binding
- Remote data with ODataAdaptor, ODataV4Adaptor, WebApiAdaptor
- Entity Framework integration
- Observable collections with dynamic data updates
- Load on Demand for large datasets
- Adding/removing items dynamically
- GetTreeViewData method for retrieving node information
Events and Callbacks
📄 Read: references/events-callbacks.md
- Lifecycle events (Created, Destroyed)
- Popup events (OnPopupOpen, OnPopupClose)
- Selection events (ValueChanging, ValueChanged)
- Filtering event with custom filters
- OnActionFailure for error handling
- Event handlers and async support
Filtering and Search
📄 Read: references/filtering-search.md
- AllowFiltering property to enable search
- FilterType options (StartsWith, EndsWith, Contains)
- IgnoreCase for case-insensitive filtering
- FilterBarPlaceholder customization
- Minimum filter length implementation
Sorting
📄 Read: references/sorting.md
- SortOrder property (None, Ascending, Descending)
- Dynamic sorting updates
Templates and Customization
📄 Read: references/templates-customization.md
- ItemTemplate for custom node rendering
- ValueTemplate for selected value display
- HeaderTemplate for popup header customization
- Advanced styling and layout patterns
Styling and Appearance
📄 Read: references/styling-appearance.md
- Disabled state configuration
- CssClass property with predefined classes (e-success, e-warning, e-error, e-outline)
- PopupWidth and PopupHeight customization
- ZIndex for layer management
- Theme support and responsive design
Form Validation and Configuration
📄 Read: references/validation-localization.md
- Form validation integration
- Value binding in forms
- Localization support
- PopupSettings configuration
- Accessibility and placeholder settings
Quick Start Example
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Common Patterns
Pattern 1: Multi-Selection with Checkboxes
Enable checkbox-based selection with automatic parent-child state management:
<SfDropDownTree TItem="EmployeeData" TValue="string"
ShowCheckBox="true"
AutoUpdateCheckState="true"
ShowSelectAll="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data"
ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>Pattern 2: Preselected Values
Set default selected nodes using @bind-Value with AllowMultiSelection:
<SfDropDownTree TItem="EmployeeData" TValue="string"
AllowMultiSelection="true"
@bind-Value="@SelectedIds">
<DropDownTreeField TItem="EmployeeData" DataSource="Data"
ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
@code {
List<string> SelectedIds = new List<string>() { "1", "5" };
}Pattern 3: Search with Filtering
Enable search functionality with custom filter types:
<SfDropDownTree TItem="EmployeeData" TValue="string"
AllowFiltering="true"
FilterType="FilterType.Contains"
FilterBarPlaceholder="Search employees...">
<DropDownTreeField TItem="EmployeeData" DataSource="Data"
ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>Pattern 4: Remote Data Binding (OData)
Bind to remote OData services with DataManager:
<SfDropDownTree TValue="int?" TItem="TreeData" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="TreeData" Query="@Query"
ID="EmployeeID" Text="FirstName" ParentID="ReportsTo" HasChildren="HasChildren">
<SfDataManager Url="url"
Adaptor="Syncfusion.Blazor.Adaptors.ODataV4Adaptor"
CrossDomain="true">
</SfDataManager>
</DropDownTreeField>
</SfDropDownTree>
@code {
public Query Query = new Query();
}Key Properties and APIs
| Property | Type | Description |
|---|---|---|
TItem | Generic | Model class for data items |
TValue | Generic | Type of selected value(s) |
Value | List<TValue> | Two-way bindable selected values |
DataSource | IEnumerable | Local data source (via DropDownTreeField) |
AllowMultiSelection | bool | Enable multi-node selection |
ShowCheckBox | bool | Display checkboxes for selection |
AutoUpdateCheckState | bool | Auto-sync parent-child checkbox states |
ShowSelectAll | bool | Display select/deselect all checkbox |
AllowFiltering | bool | Enable search filtering |
FilterType | FilterType | Filter matching strategy (StartsWith, EndsWith, Contains) |
IgnoreCase | bool | Case-insensitive filtering |
LoadOnDemand | bool | Lazy-load child nodes on expand |
Placeholder | string | Input placeholder text |
Width | string | Component width |
PopupWidth | string | Dropdown popup width |
PopupHeight | string | Dropdown popup height |
ZIndex | int | CSS z-index of popup |
CssClass | string | Custom CSS classes |
Disabled | bool | Disable component interaction |
Key Events
- Created: Component initialization complete
- Destroyed: Component destruction
- OnPopupOpen: Popup opened after animation
- OnPopupClose: Popup closed after animation
- ValueChanging: Before value change (DdtChangeEventArgs<TValue>)
- ValueChanged: After value change (List<TValue>)
- Filtering: Search text entered (DdtFilteringEventArgs)
- OnActionFailure: Error during data operations
Key Methods
- SelectAllAsync(): Programmatically select all nodes
- SelectAllAsync(false): Programmatically deselect all nodes
- ClearAsync(): Clear all selected values
- GetTreeViewData(id): Get node information by ID
Checkbox Features
Table of Contents
ShowCheckBox Property
Enable checkbox-based selection by setting the ShowCheckBox property to true. When enabled, a checkbox appears before each item text in the popup, allowing users to select multiple nodes.
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
ShowCheckBox="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Auto Update Check State
Enable automatic parent-child checkbox state synchronization using the AutoUpdateCheckState property. When enabled:
- If one or more child items are unchecked, the parent checkbox shows intermediate state
- If all child items are checked, the parent checkbox is also checked
- If a parent checkbox is checked, all child items are automatically checked
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
ShowCheckBox="true"
AutoUpdateCheckState="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Select/Unselect All
Provide a checkbox in the popup header to select or deselect all tree items using the ShowSelectAll property:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="SelectAllNode">Select all node</SfButton>
<SfButton OnClick="UnSelectAllNode">UnSelect all node</SfButton>
<div style="padding-top:20px">
<SfDropDownTree @ref="sfDropDownTree" TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
ShowCheckBox="true"
ShowSelectAll="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
</div>
@code {
SfDropDownTree<string, EmployeeData>? sfDropDownTree;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
async Task SelectAllNode()
{
await sfDropDownTree.SelectAllAsync();
}
async Task UnSelectAllNode()
{
await sfDropDownTree.SelectAllAsync(false);
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Programmatic Selection
SelectAllAsync() Method
Select all tree nodes programmatically:
await sfDropDownTree.SelectAllAsync();Parameters: None (defaults to true)
Returns: Task
SelectAllAsync(bool) Method
Select or deselect all tree nodes programmatically by passing a boolean parameter:
// Select all
await sfDropDownTree.SelectAllAsync(true);
// Deselect all
await sfDropDownTree.SelectAllAsync(false);Parameters:
value(bool):trueto select all,falseto deselect all
Returns: Task
Complete Example with Programmatic Control
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<div style="margin-bottom: 20px">
<SfButton OnClick="SelectAll">Select All</SfButton>
<SfButton OnClick="DeselectAll">Deselect All</SfButton>
<SfButton OnClick="GetSelectedCount">Get Selected Count</SfButton>
</div>
<SfDropDownTree @ref="tree" TItem="EmployeeData" TValue="string"
Placeholder="Select employees"
Width="500px"
ShowCheckBox="true"
AutoUpdateCheckState="true"
@bind-Value="@SelectedValues">
<DropDownTreeField TItem="EmployeeData" DataSource="Data"
ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
<div style="margin-top: 20px">
<p>Selected Count: @(SelectedValues?.Count ?? 0)</p>
<p>Selected IDs: @string.Join(", ", SelectedValues ?? new List<string>())</p>
</div>
@code {
SfDropDownTree<string, EmployeeData>? tree;
List<string> SelectedValues = new List<string>();
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King" },
};
async Task SelectAll()
{
await tree.SelectAllAsync(true);
}
async Task DeselectAll()
{
await tree.SelectAllAsync(false);
}
void GetSelectedCount()
{
// SelectedValues is automatically updated through @bind-Value
Console.WriteLine($"Total selected: {SelectedValues.Count}");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}CheckBox State Behavior
Without AutoUpdateCheckState (default)
- Parent and child checkbox states are independent
- Selecting a child does not affect parent
- Selecting a parent does not affect children
With AutoUpdateCheckState
| Condition | Behavior |
|---|---|
| All children checked | Parent is checked |
| Some children unchecked | Parent shows intermediate state |
| All children unchecked | Parent is unchecked |
| Parent checked | All children automatically checked |
| Parent unchecked | All children automatically unchecked |
API Properties
| Property | Type | Default | Description |
|---|---|---|---|
ShowCheckBox | bool | false | Displays checkboxes for all nodes |
AutoUpdateCheckState | bool | false | Auto-sync parent-child checkbox states |
ShowSelectAll | bool | false | Display select/deselect all checkbox in header |
@bind-Value | List<TValue> | null | Two-way bind to selected node IDs |
Related Methods
SelectAllAsync()- Select all nodesSelectAllAsync(bool)- Select or deselect all nodesClearAsync()- Clear all selections
Data Binding and Operations
Table of Contents
- Local Data Binding
- Hierarchical Data
- Self-Referential Data
- ExpandoObject Binding
- DynamicObject Binding
- Remote Data Binding
- OData Adaptor
- OData V4 Adaptor
- Web API Adaptor
- Entity Framework Integration
- Observable Collections
- Load On Demand
- Dynamic Data Operations
- GetTreeViewData Method
Local Data Binding
Bind to a list of local objects using the DataSource property of DropDownTreeField:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Hierarchical Data
Bind data with nested child collections:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TValue="string" TItem="MailItem" Placeholder="Select a Folder" Width="500px">
<DropDownTreeField TItem="MailItem"
ID="Id"
Text="FolderName"
Child="SubFolders"
DataSource="@MyFolder"
Expanded="Expanded">
</DropDownTreeField>
</SfDropDownTree>
@code {
public class MailItem
{
public string? Id { get; set; }
public string? FolderName { get; set; }
public bool Expanded { get; set; }
public List<MailItem>? SubFolders { get; set; }
}
List<MailItem> MyFolder = new List<MailItem>()
{
new MailItem
{
Id = "01",
FolderName = "Inbox",
SubFolders = new List<MailItem>()
{
new MailItem
{
Id = "01-01",
FolderName = "Categories",
SubFolders = new List<MailItem>()
{
new MailItem { Id = "01-02", FolderName = "Primary" },
new MailItem { Id = "01-03", FolderName = "Social" },
new MailItem { Id = "01-04", FolderName = "Promotions" }
}
}
}
},
new MailItem
{
Id = "02",
FolderName = "Others",
Expanded = true,
SubFolders = new List<MailItem>()
{
new MailItem { Id = "02-01", FolderName = "Sent Items" },
new MailItem { Id = "02-02", FolderName = "Delete Items" },
new MailItem { Id = "02-03", FolderName = "Drafts" }
}
}
};
}Self-Referential Data
Bind data with parent-child relationships using ParentID:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TValue="string" TItem="MailItem" Placeholder="Select a Folder" Width="500px">
<DropDownTreeField TItem="MailItem"
ID="Id"
DataSource="@MyFolder"
Text="FolderName"
ParentID="ParentId"
HasChildren="HasSubFolders"
Expanded="Expanded">
</DropDownTreeField>
</SfDropDownTree>
@code {
List<MailItem> MyFolder = new List<MailItem>
{
new MailItem { Id = "1", FolderName = "Inbox", HasSubFolders = true, Expanded = false },
new MailItem { Id = "2", ParentId = "1", FolderName = "Categories", HasSubFolders = true, Expanded = false },
new MailItem { Id = "3", ParentId = "2", FolderName = "Primary", HasSubFolders = false },
new MailItem { Id = "4", ParentId = "2", FolderName = "Social", HasSubFolders = false },
new MailItem { Id = "5", ParentId = "2", FolderName = "Promotions", HasSubFolders = false },
new MailItem { Id = "6", FolderName = "Others", HasSubFolders = true, Expanded = true },
new MailItem { Id = "7", ParentId = "6", FolderName = "Sent Items", HasSubFolders = false },
new MailItem { Id = "8", ParentId = "6", FolderName = "Delete Items", HasSubFolders = false },
new MailItem { Id = "9", ParentId = "6", FolderName = "Drafts", HasSubFolders = false },
new MailItem { Id = "10", ParentId = "6", FolderName = "Archive", HasSubFolders = false }
};
public class MailItem
{
public string? Id { get; set; }
public string? ParentId { get; set; }
public string? FolderName { get; set; }
public bool Expanded { get; set; }
public bool HasSubFolders { get; set; }
}
}ExpandoObject Binding
Bind to dynamic objects without compile-time type knowledge:
@using Syncfusion.Blazor.Navigations
@using System.Dynamic
<SfDropDownTree TValue="string" TItem="ExpandoObject" Placeholder="Select a Item">
<DropDownTreeField TItem="ExpandoObject"
ID="ID"
DataSource="@TreeData"
Text="Name"
ParentID="ParentID"
HasChildren="HasChildren"
Expanded="Expanded">
</DropDownTreeField>
</SfDropDownTree>
@code {
public List<ExpandoObject>? TreeData { get; set; }
protected override void OnInitialized()
{
this.TreeData = GetData().ToList();
}
public static List<ExpandoObject> Data = new List<ExpandoObject>();
public static int ParentRecordID { get; set; }
public static int ChildRecordID { get; set; }
public static List<ExpandoObject> GetData()
{
Data.Clear();
ParentRecordID = 0;
ChildRecordID = 0;
for (var i = 1; i <= 3; i++)
{
dynamic ParentRecord = new ExpandoObject();
ParentRecord.ID = ++ParentRecordID;
ParentRecord.Name = "Parent " + i;
ParentRecord.ParentID = null;
ParentRecord.Expanded = true;
ParentRecord.HasChildren = true;
Data.Add(ParentRecord);
AddChildRecords(ParentRecordID);
}
return Data;
}
public static void AddChildRecords(int ParentId)
{
for (var i = 1; i < 3; i++)
{
dynamic ChildRecord = new ExpandoObject();
ChildRecord.ID = ++ParentRecordID;
ChildRecord.Name = "Child item" + ++ChildRecordID;
ChildRecord.ParentID = ParentId;
Data.Add(ChildRecord);
}
}
}DynamicObject Binding
Bind to DynamicObject implementations:
@using Syncfusion.Blazor.Navigations
@using System.Dynamic
<SfDropDownTree TValue="string" TItem="DynamicDictionary" Placeholder="Select a Item">
<DropDownTreeField TItem="DynamicDictionary"
ID="ID"
DataSource="@TreeData"
Text="Name"
ParentID="ParentID"
HasChildren="HasChildren"
Expanded="Expanded">
</DropDownTreeField>
</SfDropDownTree>
@code {
public List<DynamicDictionary>? TreeData { get; set; }
protected override void OnInitialized()
{
this.TreeData = GetData().ToList();
}
public static List<DynamicDictionary> Data = new List<DynamicDictionary>();
public static int ParentRecordID { get; set; }
public static int ChildRecordID { get; set; }
public static List<DynamicDictionary> GetData()
{
Data.Clear();
ParentRecordID = 0;
ChildRecordID = 0;
for (var i = 1; i <= 3; i++)
{
dynamic ParentRecord = new DynamicDictionary();
ParentRecord.ID = ++ParentRecordID;
ParentRecord.Name = "Parent " + i;
ParentRecord.ParentID = null;
ParentRecord.Expanded = true;
ParentRecord.HasChildren = true;
Data.Add(ParentRecord);
AddChildRecords(ParentRecordID);
}
return Data;
}
public static void AddChildRecords(int ParentId)
{
for (var i = 1; i < 3; i++)
{
dynamic ChildRecord = new DynamicDictionary();
ChildRecord.ID = ++ParentRecordID;
ChildRecord.Name = "Child Item " + ++ChildRecordID;
ChildRecord.ParentID = ParentId;
Data.Add(ChildRecord);
}
}
public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
return dictionary.TryGetValue(name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
public override System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames()
{
return this.dictionary?.Keys;
}
}
}Remote Data Binding
Bind to remote services using DataManager and Query properties. The DataManager component enables interaction with remote data sources.
DataManager Configuration
Key properties:
Url: Service endpoint to fetch dataAdaptor: Data adaptor type (ODataAdaptor, ODataV4Adaptor, WebApiAdaptor, etc.)CrossDomain: Allow cross-domain requests
OData Adaptor
Connect to OData services:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Data
<SfDropDownTree TValue="int?" TItem="TreeData" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="TreeData"
Query="@Query"
ID="EmployeeID"
Text="FirstName"
ParentID="ReportsTo"
HasChildren="HasChildren">
<SfDataManager Url="url"
Adaptor="@Syncfusion.Blazor.Adaptors.ODataAdaptor"
CrossDomain="true">
</SfDataManager>
</DropDownTreeField>
</SfDropDownTree>
@code {
public Query Query = new Query();
public class TreeData
{
public string EmployeeID { get; set; }
public string ReportsTo { get; set; }
public string FirstName { get; set; }
public string Designation { get; set; }
public string Country { get; set; }
public bool HasChildren { get; set; }
}
}OData V4 Adaptor
Connect to OData V4 services:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Data
<SfDropDownTree TValue="int?" TItem="TreeData" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="TreeData"
Query="@Query"
ID="EmployeeID"
Text="FirstName"
ParentID="ReportsTo"
HasChildren="HasChildren">
<SfDataManager Url="url"
Adaptor="@Syncfusion.Blazor.Adaptors.ODataV4Adaptor"
CrossDomain="true">
</SfDataManager>
</DropDownTreeField>
</SfDropDownTree>
@code {
public Query Query = new Query();
public class TreeData
{
public string EmployeeID { get; set; }
public string ReportsTo { get; set; }
public string FirstName { get; set; }
public string Designation { get; set; }
public string Country { get; set; }
public bool HasChildren { get; set; }
}
}Web API Adaptor
Connect to custom Web API endpoints:
Razor Component
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Data
<SfDropDownTree TValue="int?" TItem="NodeResult" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="NodeResult"
Query="@TreeViewQuery"
ID="ProductID"
Text="ProductName"
ParentID="pid"
HasChildren="haschild">
<SfDataManager Url="api/Nodes"
CrossDomain="true"
Adaptor="Syncfusion.Blazor.Adaptors.WebApiAdaptor">
</SfDataManager>
</DropDownTreeField>
</SfDropDownTree>
@code {
public Query TreeViewQuery = new Query();
public class NodeResult
{
public int? ProductID { get; set; }
public string? ProductName { get; set; }
public int? pid { get; set; }
public bool haschild { get; set; }
}
}Web API Controller
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
namespace DropDownTreeSample.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class NodesController : ControllerBase
{
[HttpGet]
public IEnumerable<NodeResult> Get()
{
List<NodeResult> localData = new List<NodeResult>()
{
new NodeResult { ProductID = 1, ProductName = "Parent", pid = null, haschild = true },
new NodeResult { ProductID = 2, ProductName = "Child1", pid = 1, haschild = false },
new NodeResult { ProductID = 3, ProductName = "Child2", pid = 1, haschild = true },
new NodeResult { ProductID = 4, ProductName = "Child3", pid = 1, haschild = false },
new NodeResult { ProductID = 5, ProductName = "SubChild1", pid = 3, haschild = false },
new NodeResult { ProductID = 6, ProductName = "SubChild2", pid = 3, haschild = false },
};
var data = localData.ToList();
return data;
}
public class NodeResult
{
public int? ProductID { get; set; }
public string ProductName { get; set; }
public int? pid { get; set; }
public bool haschild { get; set; }
}
}
}Entity Framework Integration
Step 1: Create DBContext Class
using Microsoft.EntityFrameworkCore;
namespace DBTree.Data
{
public class AppDBContext : DbContext
{
public AppDBContext()
{
}
public AppDBContext(DbContextOptions<AppDBContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=DBTree;Integrated Security=True");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>().HasData(
new Employee() { Id = 1, Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new Employee() { Id = 2, PId = 1, Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new Employee() { Id = 3, PId = 2, Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new Employee() { Id = 4, PId = 3, Name = "Anne Dodsworth", Job = "Developer" },
new Employee() { Id = 5, PId = 1, Name = "Nancy Davolio", Job = "Product Manager", HasChild = true }
);
}
}
}Step 2: Create Data Access Layer
using Microsoft.EntityFrameworkCore;
namespace DBTree.Data
{
public class EmployeeDataAccessLayer
{
AppDBContext db = new();
public DbSet<Employee> GetAllEmployees()
{
try
{
return db.Employees;
}
catch
{
throw;
}
}
}
}Step 3: Create Web API Controller
using DBTree.Data;
using Microsoft.AspNetCore.Mvc;
namespace DBTree.Controller
{
[Route("api/[controller]")]
[ApiController]
public class DefaultController : ControllerBase
{
EmployeeDataAccessLayer db = new EmployeeDataAccessLayer();
[HttpGet("{id}")]
public object Get()
{
var data = db.GetAllEmployees().ToList();
return data;
}
}
}Step 4: Configure Dropdown Tree Component
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Data
<SfDropDownTree TValue="int" TItem="Employee" Placeholder="Select a Employee">
<DropDownTreeField TItem="Employee" ID="Id" Text="Name" ParentID="PId" HasChildren="HasChild" Expanded="Expanded">
<SfDataManager Url="api/Default" Adaptor="Adaptors.WebApiAdaptor" CrossDomain="true"></SfDataManager>
</DropDownTreeField>
</SfDropDownTree>
@code {
public class Employee
{
public int Id { get; set; }
public int? PId { get; set; }
public string Name { get; set; }
public string Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
}
}Observable Collections
Support dynamic collections with INotifyCollectionChanged notifications:
@using Syncfusion.Blazor.Navigations
@using System.Collections.ObjectModel
<SfDropDownTree TValue="string" TItem="ObservableDatas" Placeholder="Select a Item">
<DropDownTreeField TItem="ObservableDatas"
DataSource="@ObservableData"
ID="@nameof(ObservableDatas.Id)"
Child="@nameof(ObservableDatas.Children)"
Text="@nameof(ObservableDatas.Name)"
HasChildren="@nameof(ObservableDatas.HasChild)"
Expanded="@nameof(ObservableDatas.Expanded)">
</DropDownTreeField>
</SfDropDownTree>
@code {
public ObservableCollection<ObservableDatas> ObservableData { get; set; }
protected override void OnInitialized()
{
ObservableData = ObservableDatas.GetRecords();
}
public class ObservableDatas : INotifyPropertyChanged
{
public List<ObservableDatas> Children { get; set; }
public string Id { get; set; }
private string _name { get; set; }
public string Name
{
get => _name;
set
{
_name = value;
NotifyPropertyChanged();
}
}
public bool HasChild { get; set; }
private bool _expanded = false;
public bool Expanded
{
get => _expanded;
set
{
_expanded = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static ObservableCollection<ObservableDatas> GetRecords()
{
// Return your observable collection
return new ObservableCollection<ObservableDatas>();
}
}
}Load On Demand
Lazy-load child nodes only when parent is expanded:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
LoadOnDemand="true">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", HasChild = true },
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Dynamic Data Operations
Adding New Items
Dynamically add items to the data source:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="AddData">Add Data</SfButton>
<SfDropDownTree TItem="EmployeeData" TValue="string" Placeholder="Select an employee" Width="500px" LoadOnDemand="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void AddData()
{
Data.Add(new EmployeeData() { Id = "3", PId = "2", Name = "Jack", HasChild = false });
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}GetTreeViewData Method
Retrieve complete node details or specific node information by ID:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="GetData">Get TreeData</SfButton>
<SfDropDownTree @ref="tree" TItem="EmployeeData" TValue="string" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
<span>@EmployeeList</span>
@code {
SfDropDownTree<string, EmployeeData>? tree;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "2", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
};
string EmployeeList { get; set; } = "";
public void GetData()
{
// Get node information for ID "11"
List<EmployeeData> employees = tree.GetTreeViewData("11");
// Concatenate employee details
EmployeeList = string.Join(", ", employees.Select(e => $"{e.Name} ({e.Job})"));
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Method Signature:
public List<TItem> GetTreeViewData(string nodeId)Returns a list of node objects matching the given ID. If no ID is provided, returns all tree nodes.
Events and Callbacks
Table of Contents
- Lifecycle Events
- Popup Events
- Programmatically Controlling Popup
- Selection Events
- Filtering Event
- Action Failure Event
- Event Arguments
Lifecycle Events
Created Event
Triggered once the Dropdown Tree component has been successfully created and initialized.
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
Created="OnCreated">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void OnCreated()
{
Console.WriteLine("Dropdown Tree has been created successfully");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Destroyed Event
Triggered when the Dropdown Tree component is completely destroyed, allowing cleanup operations.
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
Destroyed="DestroyHandler">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void DestroyHandler()
{
Console.WriteLine("Dropdown Tree has been destroyed");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Popup Events
OnPopupOpen Event
Triggered after the Dropdown Tree popup is opened and animation is complete.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.DropDowns
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
OnPopupOpen="OnPopupOpen">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void OnPopupOpen(PopupEventArgs args)
{
Console.WriteLine("Popup has opened");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}OnPopupClose Event
Triggered before the Dropdown Tree popup is closed after animation.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.DropDowns
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
OnPopupClose="OnPopupClose">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void OnPopupClose(PopupEventArgs args)
{
Console.WriteLine("Popup is closing");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Preventing Popup Opening and Closing
Prevent the popup from opening or closing by setting the Cancel property to true in the event arguments. This is achieved using the OnPopupOpen and OnPopupClose events with PopupEventArgs.Cancel.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.DropDowns
<SfDropDownTree @ref="sfDropDownTree" TItem="EmployeeData" TValue="string"
ID="open"
Placeholder="Select an employee"
Width="500px"
OnPopupOpen="OnPopupOpenHandler">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
<SfDropDownTree @ref="sfDropDownTree2" TItem="EmployeeData" TValue="string"
ID="Close"
Placeholder="Select an employee"
Width="500px"
OnPopupClose="OnPopupCloseHandler">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
SfDropDownTree<string, EmployeeData>? sfDropDownTree;
SfDropDownTree<string, EmployeeData>? sfDropDownTree2;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
};
void OnPopupOpenHandler(PopupEventArgs args)
{
args.Cancel = true;
}
void OnPopupCloseHandler(PopupEventArgs args)
{
args.Cancel = true;
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Programmatically Controlling Popup
ShowPopupAsync Method
You can programmatically open the Dropdown Tree popup by calling the ShowPopupAsync() method through a reference to the component instance. This is useful when you need to trigger the popup from external buttons or other events.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="OpenPopup">Open Popup</SfButton>
<div>
<SfDropDownTree @ref="sfDropDownTree"
TItem="EmployeeData"
TValue="string"
Placeholder="Select an employee"
Width="500px"
ID="dropdowntree">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
</div>
@code {
SfDropDownTree<string, EmployeeData>? sfDropDownTree;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR" }
};
async Task OpenPopup()
{
if (sfDropDownTree != null)
{
await sfDropDownTree.ShowPopupAsync();
}
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}HidePopupAsync Method
You can programmatically close the Dropdown Tree popup by calling the HidePopupAsync() method. This allows you to close the popup from buttons or after specific actions are completed.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="ClosePopup">Close Popup</SfButton>
<div>
<SfDropDownTree @ref="sfDropDownTree"
TItem="EmployeeData"
TValue="string"
Placeholder="Select an employee"
Width="500px"
ID="dropdowntree">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
</div>
@code {
SfDropDownTree<string, EmployeeData>? sfDropDownTree;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR" }
};
async Task ClosePopup()
{
if (sfDropDownTree != null)
{
await sfDropDownTree.HidePopupAsync();
}
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Both Open and Close Together
This example demonstrates using both ShowPopupAsync() and HidePopupAsync() methods with different buttons for complete control over the popup state.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="OpenPopup">Open Popup</SfButton>
<SfButton OnClick="ClosePopup">Close Popup</SfButton>
<div>
<SfDropDownTree @ref="sfDropDownTree"
TItem="EmployeeData"
TValue="string"
Placeholder="Select an employee"
Width="500px"
ID="dropdowntree">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
</div>
@code {
SfDropDownTree<string, EmployeeData>? sfDropDownTree;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR" }
};
async Task OpenPopup()
{
if (sfDropDownTree != null)
{
await sfDropDownTree.ShowPopupAsync();
}
}
async Task ClosePopup()
{
if (sfDropDownTree != null)
{
await sfDropDownTree.HidePopupAsync();
}
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Show Popup on Initial Loading
You can automatically show the popup when the component is created by calling ShowPopupAsync() in the Created event handler.
@using Syncfusion.Blazor.Navigations
<SfDropDownTree @ref="sfDropDownTree"
TItem="EmployeeData"
TValue="string"
Placeholder="Select an employee"
Width="500px"
Created="OnCreated">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
@code {
SfDropDownTree<string, EmployeeData>? sfDropDownTree;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR" }
};
async Task OnCreated()
{
if (sfDropDownTree != null)
{
await sfDropDownTree.ShowPopupAsync();
}
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Selection Events
ValueChanging Event
Triggered when an item in the popup is selected or when the model value is changed by the user (before the change is applied).
@using Syncfusion.Blazor.Popups
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
ValueChanging="ValueChanged">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
<SfDialog Width="335px" IsModal="true" @bind-Visible="Visibility">
<DialogTemplates>
<Header>Employee Details</Header>
<Content>
<p class="employee">Name - @Name</p>
<p class="employee">Role - @Role</p>
</Content>
</DialogTemplates>
<DialogButtons>
<DialogButton Content="OK" IsPrimary="true" OnClick="@DlgButtonClick" />
</DialogButtons>
</SfDialog>
@code {
private string Name { get; set; } = string.Empty;
private string Role { get; set; } = string.Empty;
private bool Visibility { get; set; }
private void DlgButtonClick()
{
this.Visibility = false;
}
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
};
void ValueChanged(DdtChangeEventArgs<string> args)
{
EmployeeData currentData = Data?.Find((item) => item.Id == args.NodeData.Id);
Name = currentData?.Name;
Role = currentData?.Job;
this.Visibility = true;
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}ValueChanged Event
Triggered after the value changes in the Dropdown Tree component. Receives a list of changed values.
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
ValueChanged="ValueChanged">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void ValueChanged(List<string> selectedIds)
{
Console.WriteLine($"Selected IDs: {string.Join(", ", selectedIds)}");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Filtering Event
Filtering Event
Triggered when the user types text in the search box. Allows custom filtering logic.
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
Filtering="OnFiltering">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void OnFiltering(DdtFilteringEventArgs args)
{
// args.Text contains the filter text
Console.WriteLine($"Filter text: {args.Text}");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Minimum Filter Length
Implement minimum character requirement before filtering:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
Filtering="OnFiltering">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
};
void OnFiltering(DdtFilteringEventArgs args)
{
// Require minimum 2 characters
if (args.Text.Length < 2)
{
args.PreventDefaultAction = true;
}
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Action Failure Event
OnActionFailure Event
Triggered when any Dropdown Tree action fails (e.g., remote data fetch error). Allows error handling and recovery.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Data
<SfDropDownTree TValue="int?" TItem="TreeData"
Placeholder="Select a name"
Width="500px"
OnActionFailure="OnActionFailureTemplate">
<ChildContent>
<DropDownTreeField TItem="TreeData" Query="@employeeQuery"
ID="EmployeeID" Text="FirstName" HasChildren="EmployeeID">
<SfDataManager Url="url"
Adaptor="Syncfusion.Blazor.Adaptors.ODataV4Adaptor"
CrossDomain="true">
</SfDataManager>
</DropDownTreeField>
</ChildContent>
<ActionFailureTemplate>
<span style="color: red;">A request to fetch data failed. Please try again.</span>
</ActionFailureTemplate>
</SfDropDownTree>
@code {
Query? employeeQuery;
protected override void OnInitialized()
{
base.OnInitialized();
employeeQuery = new Query().From("Employees").Select(new List<string> { "EmployeeID", "FirstName", "Title" }).Take(5);
}
void OnActionFailureTemplate()
{
Console.WriteLine("Data fetch failed");
}
public class TreeData
{
public int? EmployeeID { get; set; }
public string? FirstName { get; set; }
}
}Event Arguments
PopupEventArgs
Arguments for popup events (OnPopupOpen, OnPopupClose):
public class PopupEventArgs
{
public bool Cancel { get; set; } // Prevent default action
}DdtChangeEventArgs<TValue>
Arguments for ValueChanging event:
public class DdtChangeEventArgs<TValue>
{
public TValue Value { get; set; } // Selected value
public NodeData NodeData { get; set; } // Current node data
public bool Cancel { get; set; } // Prevent selection
}DdtFilteringEventArgs
Arguments for Filtering event:
public class DdtFilteringEventArgs
{
public string Text { get; set; } // Filter text
public bool PreventDefaultAction { get; set; } // Skip default filtering
}Event Execution Order
1. Component Initialization: Created 2. User Interaction:
- Popup opens →
OnPopupOpen - User selects item →
ValueChanging→ValueChanged - User searches →
Filtering - Popup closes →
OnPopupClose
3. Component Destruction: Destroyed
Filtering and Search
Table of Contents
- Enabling Filtering
- Filter Types
- Local Data Filtering
- Remote Data Filtering
- Case-Sensitive Filtering
- Filter Placeholder
- Minimum Filter Length
Enabling Filtering
Enable search functionality by setting AllowFiltering to true:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Filter Types
Available Filter Types
The FilterType property controls how filtering matches search text:
| FilterType | Description |
|---|---|
StartsWith | Match nodes where text begins with search value (default) |
EndsWith | Match nodes where text ends with search value |
Contains | Match nodes where text contains search value anywhere |
Using StartsWith (Default)
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
FilterType="FilterType.StartsWith">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
// Data as above
}Using EndsWith
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.DropDowns
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
FilterType="FilterType.EndsWith">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
// Data as above
}Using Contains
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.DropDowns
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
FilterType="FilterType.Contains">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
// Data as above
}Local Data Filtering
Filter locally bound data automatically:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth" },
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Remote Data Filtering
Filter data from remote OData services:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Data
<SfDropDownTree TValue="int?" TItem="TreeData"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true">
<DropDownTreeField TItem="TreeData"
Query="@Query"
ID="EmployeeID"
Text="FirstName"
HasChildren="EmployeeID">
<SfDataManager Url="http://services.odata.org/V4/Northwind/Northwind.svc"
Adaptor="@Syncfusion.Blazor.Adaptors.ODataV4Adaptor"
CrossDomain="true">
</SfDataManager>
</DropDownTreeField>
<DropDownTreeField TItem="TreeData"
Query="@SubQuery"
ID="OrderID"
Text="ShipName"
ParentID="EmployeeID">
<SfDataManager Url="http://services.odata.org/V4/Northwind/Northwind.svc"
Adaptor="@Syncfusion.Blazor.Adaptors.ODataV4Adaptor"
CrossDomain="true">
</SfDataManager>
</DropDownTreeField>
</SfDropDownTree>
@code {
public Query Query = new Query().From("Employees").Select(new List<string> { "EmployeeID", "FirstName" }).Take(5).RequiresCount();
public Query SubQuery = new Query().From("Orders").Select(new List<string> { "OrderID", "EmployeeID", "ShipName" }).Take(5).RequiresCount();
public class TreeData
{
public int? EmployeeID { get; set; }
public int OrderID { get; set; }
public string? ShipName { get; set; }
public string? FirstName { get; set; }
}
}Case-Sensitive Filtering
Control filtering behavior with the IgnoreCase property:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
IgnoreCase="false">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true },
new EmployeeData() { Id = "2", Name = "steven buchanan", HasChild = true },
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Note: By default, IgnoreCase is true (case-insensitive filtering)
Filter Placeholder
Customize the filter input placeholder text:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
FilterBarPlaceholder="Search by name...">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
// Data as above
}Minimum Filter Length
Implement minimum character requirement before filtering occurs:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
FilterBarPlaceholder="Search (min 2 chars)"
Filtering="OnFiltering">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King" },
};
void OnFiltering(DdtFilteringEventArgs args)
{
// Check filter text length
if (!string.IsNullOrEmpty(args.Text) && args.Text.Length < 2)
{
args.PreventDefaultAction = true;
}
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Complete Filtering Example
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.DropDowns
<div>
<div style="margin-bottom: 20px">
<label>Filter Type: </label>
<select @onchange="OnFilterTypeChange">
<option value="@FilterType.StartsWith">Starts With</option>
<option value="@FilterType.EndsWith">Ends With</option>
<option value="@FilterType.Contains">Contains</option>
</select>
</div>
<div style="margin-bottom: 20px">
<label>
<input type="checkbox" @onchange="OnIgnoreCaseChange" />
Ignore Case
</label>
</div>
</div>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true"
FilterType="@CurrentFilterType"
IgnoreCase="@CurrentIgnoreCase"
FilterBarPlaceholder="Search employees..."
Filtering="OnFiltering">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
FilterType CurrentFilterType = FilterType.StartsWith;
bool CurrentIgnoreCase = true;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", HasChild = true },
};
void OnFilterTypeChange(ChangeEventArgs e)
{
CurrentFilterType = (FilterType)Enum.Parse(typeof(FilterType), e.Value.ToString());
}
void OnIgnoreCaseChange(ChangeEventArgs e)
{
CurrentIgnoreCase = (bool)e.Value;
}
void OnFiltering(DdtFilteringEventArgs args)
{
Console.WriteLine($"Filtering text: {args.Text}");
}
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Filtering Properties Summary
| Property | Type | Default | Description |
|---|---|---|---|
AllowFiltering | bool | false | Enable/disable search filtering |
FilterType | FilterType | StartsWith | Filter matching strategy |
IgnoreCase | bool | true | Case-insensitive filtering |
FilterBarPlaceholder | string | null | Filter input placeholder text |
Filtering | EventCallback<DdtFilteringEventArgs> | null | Filter event callback |
Getting Started with Blazor Dropdown Tree
Table of Contents
- NuGet Installation
- Namespace Setup
- Service Registration
- Theme Setup
- Basic Implementation
- Setup for Web App
- Setup for Server App
NuGet Installation
The Dropdown Tree component requires the Syncfusion.Blazor.Navigations and Syncfusion.Blazor.Themes NuGet packages.
Via Package Manager Console
Install-Package Syncfusion.Blazor.Navigations -Version {{ site.releaseversion }}
Install-Package Syncfusion.Blazor.Themes -Version {{ site.releaseversion }}Via .NET CLI
dotnet add package Syncfusion.Blazor.Navigations -v {{ site.releaseversion }}
dotnet add package Syncfusion.Blazor.Themes -v {{ site.releaseversion }}
dotnet restoreNamespace Setup
Add the following namespaces to your ~/_Imports.razor file:
@using Syncfusion.Blazor
@using Syncfusion.Blazor.NavigationsService Registration
Register the Syncfusion Blazor service in your ~/Program.cs:
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Syncfusion.Blazor;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// Add Syncfusion Blazor services
builder.Services.AddSyncfusionBlazor();
await builder.Build().RunAsync();Theme Setup
Add the theme stylesheet and script reference to your ~/index.html file (inside the <head> section):
<head>
...
<!-- Syncfusion Blazor Bootstrap5 Theme -->
<link href="_content/Syncfusion.Blazor.Themes/bootstrap5.css" rel="stylesheet" />
<!-- Syncfusion Blazor Core Script -->
<script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js" type="text/javascript"></script>
</head>Available Themes:
bootstrap5.css- Bootstrap 5 Themematerial3.css- Material Design 3 Themefluent2.css- Microsoft Fluent 2 Themetailwind.css- Tailwind CSS Theme
Basic Implementation
Here's a minimal working example of the Dropdown Tree component with self-referential data:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="EmployeeData"
DataSource="Data"
ID="Id"
Text="Name"
HasChildren="HasChild"
ParentID="PId">
</DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}DropDownTreeField Properties
The DropDownTreeField component is configured with field mappings:
| Property | Type | Description |
|---|---|---|
ID | string | Maps the unique identifier field of the data item |
Text | string | Maps the text/display field of the data item |
ParentID | string | Maps the parent identifier for self-referential data |
HasChildren | string | Maps a boolean field indicating if node has children |
Child | string | Maps nested child collection (for hierarchical data) |
DataSource | IEnumerable | Specifies the local data source |
Expanded | string | Maps a boolean field for default expand state |
Setup for Web App (WebAssembly)
1. Create a new Blazor WebAssembly App using Visual Studio or CLI:
dotnet new blazorwasm -o BlazorApp
cd BlazorApp2. Install NuGet packages:
dotnet add package Syncfusion.Blazor.Navigations -v {{ site.releaseversion }}
dotnet add package Syncfusion.Blazor.Themes -v {{ site.releaseversion }}3. Update _Imports.razor:
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Navigations4. Register Syncfusion service in Program.cs:
builder.Services.AddSyncfusionBlazor();5. Add theme and script to index.html
6. Use the component in your pages
Setup for Server App
1. Create a new Blazor Server App using Visual Studio or CLI:
dotnet new blazorserver -o BlazorServerApp
cd BlazorServerApp2. Install NuGet packages:
dotnet add package Syncfusion.Blazor.Navigations -v {{ site.releaseversion }}
dotnet add package Syncfusion.Blazor.Themes -v {{ site.releaseversion }}3. Update _Imports.razor:
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Navigations4. Register Syncfusion service in Program.cs:
builder.Services.AddSyncfusionBlazor();5. Add theme and script to _Layout.cshtml (in the <head> section):
<link href="_content/Syncfusion.Blazor.Themes/bootstrap5.css" rel="stylesheet" />
<script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js" type="text/javascript"></script>6. Use the component in your pages
Data Binding Modes
Self-Referential Data
Data with ParentID relationship:
List<TreeItem> data = new List<TreeItem>
{
new TreeItem { Id = "1", Name = "Parent", ParentId = null },
new TreeItem { Id = "2", Name = "Child 1", ParentId = "1" },
new TreeItem { Id = "3", Name = "Child 2", ParentId = "1" }
};Hierarchical Data
Nested collection of objects:
List<TreeItem> data = new List<TreeItem>
{
new TreeItem
{
Id = "1",
Name = "Parent",
Children = new List<TreeItem>
{
new TreeItem { Id = "2", Name = "Child 1" },
new TreeItem { Id = "3", Name = "Child 2" }
}
}
};Configure with:
<DropDownTreeField TItem="TreeItem"
DataSource="data"
ID="Id"
Text="Name"
Child="Children">
</DropDownTreeField>Rendering
The Dropdown Tree component renders as:
- Input field: Displays selected item(s)
- Toggle button: Opens/closes the tree popup
- Popup container: Contains the tree structure with nodes and hierarchy
Each tree node shows:
- Expand/collapse icon (if has children)
- Node text
- Checkbox (if ShowCheckBox is true)
Selection and Modes
Table of Contents
- Single Selection
- Multi-Selection
- Preselected Values
- Getting Selected Values
- Clear Selection
- Two-Way Binding
- Keyboard Shortcuts
Single Selection
By default, the Dropdown Tree allows only single node selection. When a node is selected, the popup closes automatically and the selected node text appears in the input box.
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Multi-Selection
Enable multi-selection by setting the AllowMultiSelection property to true. Users can select multiple nodes using:
- CTRL + Click: Select/deselect individual nodes
- SHIFT + Click: Select a range of nodes
- Checkbox: If
ShowCheckBoxis enabled
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowMultiSelection="true">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Preselected Values
Set initial selection using the Value property with @bind-Value directive:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="SelectANode">Select a node</SfButton>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowMultiSelection="true"
@bind-Value="@SelectedNode">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<string> SelectedNode = new List<string>() { "1", "5" };
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
void SelectANode()
{
SelectedNode = new List<string>() { "9" };
}
class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Getting Selected Values
Access selected values through two-way binding with the @bind-Value directive:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowMultiSelection="true"
@bind-Value="@SelectedNode">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
<table style="margin-left: 600px; margin-top: -50px;">
<thead>
<tr>
<th style="width: 50%">Selected Ids</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < SelectedNode?.Count; i++)
{
<tr>
<td style="width: 30%">
<div>@SelectedNode[i]</div>
</td>
</tr>
}
</tbody>
</table>
@code {
List<string> SelectedNode = new List<string>() { "5" };
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Note: The Value property is always a List<TValue>, even in single-selection mode.
Clear Selection
Clear all selected values using the ClearAsync() method:
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="ClearNode">Clear node</SfButton>
<SfDropDownTree @ref="sfDropDownTree" TItem="EmployeeData" TValue="string" Placeholder="Select an employee" Width="500px">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
SfDropDownTree<string, EmployeeData>? sfDropDownTree;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
async Task ClearNode()
{
await sfDropDownTree.ClearAsync();
}
class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Two-Way Binding
Use the @bind-Value directive for two-way binding of selected values:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
@bind-Value="@value">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
List<string> value = new List<string>(){"1"};
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Keyboard Shortcuts
When AllowMultiSelection is enabled:
| Shortcut | Action |
|---|---|
CTRL + Click | Select or deselect individual nodes |
SHIFT + Click | Select a contiguous range of nodes |
CTRL + A | Select all nodes (with appropriate filtering) |
Arrow Keys | Navigate between nodes when popup is open |
Space | Toggle selection of current node |
Enter | Confirm selection and close popup |
Esc | Close popup without changing selection |
Sorting
Table of Contents
Overview
The Dropdown Tree component allows you to sort nodes in Ascending or Descending order. The sorting is controlled by the SortOrder property.
SortOrder Property
The SortOrder property supports the following values:
- None: Nodes are not sorted (default).
- Ascending: Nodes are sorted in ascending order.
- Descending: Nodes are sorted in descending order.
Dynamic Sorting Example
You can dynamically update the sorting order by binding the SortOrder property to a component variable and updating it via user interaction.
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.Buttons
<SfButton OnClick="Ascending">Ascending Order</SfButton>
<SfButton OnClick="Descending">Descending Order</SfButton>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
SortOrder="sortOrder">
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</SfDropDownTree>
@code {
public Syncfusion.Blazor.Navigations.SortOrder sortOrder;
// ... Data source definition ...
public void Ascending()
{
sortOrder = Syncfusion.Blazor.Navigations.SortOrder.Ascending;
}
public void Descending()
{
sortOrder = Syncfusion.Blazor.Navigations.SortOrder.Descending;
}
}Styling and Appearance
Table of Contents
CSS Classes
The Dropdown Tree component supports built-in CSS classes for styling:
Success Style
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
CssClass="e-success">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true }
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public string? PId { get; set; }
}
}Available CSS Classes
| CSS Class | Style | Use Case |
|---|---|---|
e-success | Green border and focus color | Success/valid state |
e-warning | Yellow/orange border and focus color | Warning/caution state |
e-error | Red border and focus color | Error/invalid state |
e-outline | Outlined style variant | Alternative appearance |
Warning Style Example
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select with caution"
CssClass="e-warning">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>Error Style Example
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select a valid option"
CssClass="e-error">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>Disabled State
Disable the component using the Enabled property:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Enabled="false">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan" }
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public string? PId { get; set; }
}
}Behavior when disabled:
- Input field becomes read-only
- Dropdown cannot be opened
- Selection cannot be changed
- Appears with reduced opacity/gray styling
- Tab focus not allowed
Conditional Enabling
@using Syncfusion.Blazor.Navigations
<button @onclick="@(() => { isEnabled = !isEnabled; })">Toggle Enable</button>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Enabled="isEnabled">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
@code {
bool isEnabled = true;
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan" }
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public string? PId { get; set; }
}
}CssClass Property
Apply custom CSS classes to the component:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
CssClass="my-custom-dropdown e-success">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan" }
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public string? PId { get; set; }
}
}
<style>
.my-custom-dropdown {
border: 2px solid #667eea !important;
border-radius: 8px !important;
}
.my-custom-dropdown.e-focus::before {
border-color: #667eea !important;
}
.my-custom-dropdown .e-input {
font-size: 16px;
padding: 12px;
}
</style>Popup Sizing
Control popup dimensions using PopupWidth and PopupHeight:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
PopupWidth="100%"
PopupHeight="300px">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller" },
new EmployeeData() { Id = "4", PId = "1", Name = "Nancy Davolio" },
new EmployeeData() { Id = "5", Name = "Michael Suyama", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Robert King" }
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Popup Sizing Properties
| Property | Type | Default | Description |
|---|---|---|---|
PopupWidth | string | 100% | Width of popup container (px, %, auto) |
PopupHeight | string | 300px | Height of popup container (px, auto) |
Responsive Popup
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
PopupWidth="calc(100% - 20px)"
PopupHeight="auto">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>Z-Index Control
Set popup layer depth using PopupSettings:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
<DropDownTreePopupSettings ZIndex="9999"></DropDownTreePopupSettings>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan" }
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public string? PId { get; set; }
}
}Z-Index Usage:
- Default ZIndex: 1000
- Use higher values for overlays over modals
- Use lower values for components that shouldn't overlap other elements
Theme Support
The Dropdown Tree component supports multiple Syncfusion themes:
Bootstrap Theme
<link href="_content/Syncfusion.Blazor.Themes/bootstrap5.css" rel="stylesheet" />Material Theme
<link href="_content/Syncfusion.Blazor.Themes/material.css" rel="stylesheet" />Tailwind CSS Theme
<link href="_content/Syncfusion.Blazor.Themes/tailwind.css" rel="stylesheet" />Fluent Theme
<link href="_content/Syncfusion.Blazor.Themes/fluent.css" rel="stylesheet" />Complete Styling Example
@using Syncfusion.Blazor.Navigations
<div class="container">
<h3>Dropdown Tree Styling</h3>
<div class="form-group">
<label>Success State:</label>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Valid selection"
CssClass="e-success"
PopupWidth="100%"
PopupHeight="250px">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
</div>
<div class="form-group">
<label>Warning State:</label>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Verify before selecting"
CssClass="e-warning">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
</div>
<div class="form-group">
<label>Error State:</label>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Required field"
CssClass="e-error">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
</div>
<div class="form-group">
<label>Disabled State:</label>
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Disabled"
Enabled="false">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
</SfDropDownTree>
</div>
</div>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller" },
new EmployeeData() { Id = "4", PId = "1", Name = "Nancy Davolio" }
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}
<style>
.container {
max-width: 600px;
margin: 20px auto;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #333;
}
.form-group ::deep .e-ddtree-wrapper {
width: 100%;
margin-bottom: 10px;
}
</style>Styling Properties Reference
| Property | Type | Purpose |
|---|---|---|
CssClass | string | Additional CSS classes (e-success, e-warning, e-error, e-outline) |
Enabled | bool | Enable/disable the component |
PopupWidth | string | Width of popup (px, %, auto) |
PopupHeight | string | Height of popup (px, auto) |
Width | string | Width of the input element |
Height | string | Height of the input element |
Custom CSS Integration
/* Override Syncfusion styles */
.e-ddtree .e-list-item {
padding: 12px !important;
}
.e-ddtree .e-list-item:hover {
background-color: #f0f0f0 !important;
}
.e-ddtree .e-list-item.e-active {
background-color: #667eea !important;
}
.e-ddtree-wrapper input.e-field {
border-radius: 4px !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
}Templates and Customization
Table of Contents
Item Template
Customize the rendering of each tree node in the popup using the ItemTemplate:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
<ItemTemplate>
<div>
<span class="ename">@((context as EmployeeData).Name) - </span>
<span class="ejob" style="opacity: .60">@((context as EmployeeData).Job)</span>
</div>
</ItemTemplate>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Key Points:
contextcontains the current node data- Template is applied to all nodes in the tree
- Supports inline HTML and Blazor components
- Variable
contextis of typeEmployeeData(cast as needed)
Item Template with Icons
<ItemTemplate>
<div style="display: flex; align-items: center; gap: 10px;">
@if (((context as EmployeeData).HasChild))
{
<span class="e-icons e-folder" style="font-size: 18px;"></span>
}
else
{
<span class="e-icons e-file" style="font-size: 18px;"></span>
}
<div>
<span style="font-weight: 500;">@((context as EmployeeData).Name)</span>
<br />
<span style="font-size: 12px; color: #888;">@((context as EmployeeData).Job)</span>
</div>
</div>
</ItemTemplate>Value Template
Customize the display of the selected value in the input box using the ValueTemplate:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId" Expanded="Expanded"></DropDownTreeField>
</ChildContent>
<ValueTemplate>
<span>@((context as EmployeeData).Name) - @((context as EmployeeData).Job)</span>
</ValueTemplate>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Key Points:
contextcontains the selected node data- Template is applied only to selected value display
- Used to format selected value differently from item display
- Supports multi-selection formatting
Multi-Selection Value Display
<ValueTemplate>
<div style="padding: 5px 0;">
@if (@context is List<EmployeeData> selectedItems)
{
@foreach (var item in selectedItems.Take(2))
{
<span style="background: #ddd; padding: 2px 8px; margin-right: 5px; border-radius: 3px;">@item.Name</span>
}
@if (selectedItems.Count > 2)
{
<span style="background: #ddd; padding: 2px 8px; border-radius: 3px;">+@(selectedItems.Count - 2)</span>
}
}
</div>
</ValueTemplate>Header Template
Customize the popup header using the HeaderTemplate:
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
CssClass="custom">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
<HeaderTemplate>
<div class="head"> Employee List </div>
</HeaderTemplate>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth" },
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Advanced Header with Controls
<HeaderTemplate>
<div style="display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; border-bottom: 1px solid #ddd;">
<span style="font-weight: 600;">Select Employee</span>
<span style="font-size: 12px; color: #888;">@Data?.Count items</span>
</div>
</HeaderTemplate>Advanced Customization
Complete Custom Template Example
@using Syncfusion.Blazor.Navigations
<SfDropDownTree TItem="EmployeeData" TValue="string"
Placeholder="Select an employee"
Width="500px"
AllowFiltering="true">
<ChildContent>
<DropDownTreeField TItem="EmployeeData" DataSource="Data" ID="Id" Text="Name" HasChildren="HasChild" ParentID="PId"></DropDownTreeField>
</ChildContent>
<HeaderTemplate>
<div style="background: #f5f5f5; padding: 12px 15px; border-bottom: 1px solid #ddd;">
<strong>Organizational Structure</strong>
<p style="margin: 5px 0; font-size: 12px; color: #666;">Select an employee</p>
</div>
</HeaderTemplate>
<ItemTemplate>
<div style="padding: 8px 5px; display: flex; align-items: center; gap: 10px;">
<div style="width: 35px; height: 35px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold;">
@((context as EmployeeData).Name?[0] ?? 'E')
</div>
<div style="flex: 1;">
<div style="font-weight: 500;">@((context as EmployeeData).Name)</div>
<div style="font-size: 12px; color: #666;">@((context as EmployeeData).Job)</div>
</div>
@if (((context as EmployeeData).HasChild))
{
<span class="e-icons" style="color: #999;">+</span>
}
</div>
</ItemTemplate>
<ValueTemplate>
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 25px; height: 25px; background: #667eea; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 12px; font-weight: bold;">
@((context as EmployeeData).Name?[0] ?? 'E')
</div>
<span>@((context as EmployeeData).Name)</span>
</div>
</ValueTemplate>
</SfDropDownTree>
@code {
List<EmployeeData> Data = new List<EmployeeData>
{
new EmployeeData() { Id = "1", Name = "Steven Buchanan", Job = "General Manager", HasChild = true, Expanded = true },
new EmployeeData() { Id = "2", PId = "1", Name = "Laura Callahan", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "3", PId = "2", Name = "Andrew Fuller", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "4", PId = "3", Name = "Anne Dodsworth", Job = "Developer" },
new EmployeeData() { Id = "10", PId = "3", Name = "Lilly", Job = "Developer" },
new EmployeeData() { Id = "5", PId = "1", Name = "Nancy Davolio", Job = "Product Manager", HasChild = true },
new EmployeeData() { Id = "6", PId = "5", Name = "Michael Suyama", Job = "Team Lead", HasChild = true },
new EmployeeData() { Id = "7", PId = "6", Name = "Robert King", Job = "Developer" },
new EmployeeData() { Id = "11", PId = "6", Name = "Mary", Job = "Developer" },
new EmployeeData() { Id = "9", PId = "1", Name = "Janet Leverling", Job = "HR"}
};
public class EmployeeData
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Job { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public string? PId { get; set; }
}
}Template Context Type
When using templates, the context variable contains the node data:
// Cast to access data properties
var employee = (context as EmployeeData);
var name = employee?.Name;
var job = employee?.Job;
var hasChildren = employee?.HasChild ?? false;Template Styling
Templates support inline styles and CSS classes:
<!-- Inline styles -->
<div style="color: red; font-weight: bold;">
@((context as EmployeeData).Name)
</div>
<!-- CSS classes -->
<div class="employee-item">
@((context as EmployeeData).Name)
</div>/* In component or global CSS */
.employee-item {
padding: 8px;
background-color: #f9f9f9;
border-left: 3px solid #667eea;
}Template Best Practices
1. Performance: Minimize complex logic in templates 2. Accessibility: Include alt text for images and proper ARIA labels 3. Responsive: Use flexible layouts for mobile support 4. Consistency: Match template styling across item, value, and header 5. Null Handling: Always check for null values before accessing properties 6. Type Safety: Cast context to specific type for IntelliSense support