Skip to content

Tree Views — cdx_tree_view

cdx_tree_view is the CDX hierarchy package. Use it when users need to choose a parent, folder, area, collection, or other container before working with a detail surface.

The package wraps Flutter's two-dimensional tree renderer but keeps the public API in CDX terms:

dart
import 'package:cdx_tree_view/cdx_tree_view.dart';

Live Example

Open the full route: Tree View.

When To Use It

Use a tree when the primary question is where does this item belong? The tree should usually provide context, not replace the detail view.

Good fits:

ScenarioPattern
Areas and equipmentSelect an area, show equipment or activities on the right
Folders and documentsSelect a folder, show documents or metadata on the right
Product librariesSelect a category, show SKUs or forms on the right
Entity managementUse hierarchy selection as a base filter for a normal collection

Model

Tree view data flowA tree data source loads roots and children. The controller owns expansion and selection. CdxTreeSplitView renders the tree and passes the selected item to a detail builder.DataSourceloadRoots +loadChildren(parent)Controllerroots, expansion,selectionSplit Viewtree rail + hostdetail builderselected item becomes detail context
text
CdxTreeDataSource<T>
  -> CdxTreeController<T>
  -> CdxTreeView<T>
  -> CdxTreeSplitView<T>

CdxTreeDataSource<T> loads roots and children. CdxTreeController<T> owns raw MobX state, expansion, selection, loading, and errors. CdxTreeView<T> renders the hierarchy. CdxTreeSplitView<T> pairs the tree with any detail builder.

Data Source

dart
class FolderTreeDataSource extends CdxTreeDataSource<Folder> {
  FolderTreeDataSource(this.api);

  final FolderApi api;

  @override
  Future<List<CdxTreeItem<Folder>>> loadRoots() async {
    final folders = await api.childrenOf(null);
    return [
      for (final folder in folders)
        CdxTreeItem(
          id: folder.id,
          value: folder,
          title: folder.name,
          hasChildren: folder.hasChildren,
        ),
    ];
  }

  @override
  Future<List<CdxTreeItem<Folder>>> loadChildren(
    CdxTreeItem<Folder> parent,
  ) async {
    final folders = await api.childrenOf(parent.id);
    return [
      for (final folder in folders)
        CdxTreeItem(
          id: folder.id,
          value: folder,
          title: folder.name,
          hasChildren: folder.hasChildren,
        ),
    ];
  }
}

Split View

dart
final controller = CdxTreeController<Folder>(
  dataSource: FolderTreeDataSource(api),
  eagerDepth: 1,
);

CdxTreeSplitView<Folder>(
  controller: controller,
  detailBuilder: (context, selected) {
    if (selected == null) {
      return const EmptyState(title: 'Select a folder');
    }

    return DocumentsTable(folderId: selected.value.id);
  },
);

The selected item can drive a table, kanban board, form, read-only detail, or any other widget.

Controller API

dart
await controller.load(selectFirst: true);
await controller.ensureChildrenLoaded(node, expandAfterLoad: true);
await controller.toggleNode(node);
await controller.reloadNode(node);

controller.select(item);
controller.clearSelection();

Use eagerDepth for shallow hierarchies where the first few levels should be loaded immediately. Leave it at the lazy default when a hierarchy can be large.

API Parameters

TypeParameterPurpose
CdxTreeDataSourceloadRoots()Load top-level containers.
CdxTreeDataSourceloadChildren(parent)Load child containers for a node.
CdxTreeControllereagerDepthPrefetch descendants after each load; 0 means roots only.
CdxTreeController.loadselectFirstSelect the first root after loading.
CdxTreeViewautoLoad, selectFirstOnLoadWidget-level initial load behavior.
CdxTreeViewrowExtent, indent, nodeBuilderRow sizing and custom row rendering.
CdxTreeSplitViewtreeWidth, minTreeWidth, maxTreeWidthResizable rail constraints.
CdxTreeSplitViewdetailBuilderHost-owned detail surface for controller.selectedItem.

Entity-System Pattern

In entity-system UI, treat the tree as a context selector. The selected node contributes a base filter to the right-hand surface:

text
selected tree node filter
AND detail table or kanban filter
AND detail search and sort

Do not let table filters prune the tree. The hierarchy should remain stable while the detail surface behaves like a normal entity collection.