diff --git a/src/ScadaLink.CentralUI/Components/Shared/TreeView.razor b/src/ScadaLink.CentralUI/Components/Shared/TreeView.razor
new file mode 100644
index 0000000..fcc9981
--- /dev/null
+++ b/src/ScadaLink.CentralUI/Components/Shared/TreeView.razor
@@ -0,0 +1,106 @@
+@* Reusable hierarchical tree view with expand/collapse, ARIA roles, and guide lines *@
+@typeparam TItem
+
+@if (_items is null || _items.Count == 0)
+{
+ if (EmptyContent != null)
+ {
+ @EmptyContent
+ }
+}
+else
+{
+
+ @foreach (var item in _items)
+ {
+ RenderNode(item, 0);
+ }
+
+}
+
+@{ void RenderNode(TItem item, int depth)
+ {
+ var key = KeySelector(item);
+ var children = ChildrenSelector(item);
+ var isBranch = HasChildrenSelector(item);
+ var isExpanded = _expandedKeys.Contains(key);
+
+
+
+ @if (isBranch)
+ {
+ ToggleExpand(key)">@(isExpanded ? "\u2212" : "+")
+ }
+ else
+ {
+
+ }
+
+ @NodeContent(item)
+
+
+ @if (isBranch && isExpanded && children is { Count: > 0 })
+ {
+
+ @foreach (var child in children)
+ {
+ RenderNode(child, depth + 1);
+ }
+
+ }
+
+ }
+}
+
+@code {
+ private IReadOnlyList? _items;
+ private HashSet