Searchable Tree

A highly customizable Flutter tree view widget with built-in search support, expand/collapse functionality, and beautiful UI. Perfect for displaying hierarchical data structures with a great user experience.

Features

  • πŸ” Built-in Search: Instant search functionality with automatic match highlighting
  • 🎨 Highly Customizable: Customize colors, text styles, icons, and more to match your app's design
  • πŸ“± Responsive Design: Auto-wrap text for long titles, smooth animations, and touch-friendly interactions
  • πŸ“Š Hierarchy Visualization: Indentation guide lines to clearly show tree structure
  • ⚑ Performance Optimized: Efficient rendering even for large tree structures
  • πŸ”§ Flexible Configuration: Enable/disable features as needed
  • 🎯 Node Selection: Selectable nodes with visual feedback and auto-scroll
  • βž• Add Button: Built-in add button for creating new nodes
  • 🍱 Context Menu: Support for node context menus with custom positioning
  • 🎯 Initial Selection: Set initial selected node on widget load

Demo

Demo

Getting started

Add the package to your pubspec.yaml:

dependencies:
  searchable_tree: ^0.0.2

Import the package in your Dart code:

import 'package:searchable_tree/searchable_tree.dart';

Usage

Basic Example

// Create tree nodes
final List<TreeNode> nodes = [
  TreeNode(
    id: '1',
    title: 'Parent Node 1',
    children: [
      TreeNode(id: '1-1', title: 'Child Node 1-1'),
      TreeNode(
        id: '1-2',
        title: 'Parent Node 1-2',
        children: [
          TreeNode(id: '1-2-1', title: 'Child Node 1-2-1'),
          TreeNode(id: '1-2-2', title: 'Child Node 1-2-2'),
        ],
      ),
    ],
  ),
  TreeNode(id: '2', title: 'Parent Node 2'),
];

// Use the widget
SearchableTree(
  nodes: nodes,
  onNodeTap: (node) {
    print('Tapped node: ${node.title}');
  },
  onExpandToggle: (node, isExpanded) {
    print('Node ${node.title} is now ${isExpanded ? 'expanded' : 'collapsed'}');
  },
)

Customized Example

SearchableTree(
  nodes: nodes,
  showSearchField: true,
  showExpandIcon: true,
  indentation: 32.0,
  expandIconColor: Colors.blue,
  highlightColor: Colors.yellowAccent,
  selectedColor: Colors.blue.withValues(alpha: 0.2),
  titleStyle: TextStyle(
    fontSize: 16,
    color: Colors.grey[800],
  ),
  searchFieldStyle: TextStyle(
    fontSize: 14,
  ),
  searchDecoration: InputDecoration(
    hintText: 'Search nodes...',
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
  ),
  onNodeTap: (node) {
    // Handle node tap
  },
  onExpandToggle: (node, isExpanded) {
    // Handle expand/collapse
  },
  onNodeSelected: (node, isSelected) {
    // Handle node selection
  },
  onAddButtonTap: () {
    // Handle add button tap
  },
  onNodeShowMenu: (node, position) {
    // Show context menu at position
  },
)

Without Search Field

SearchableTree(
  nodes: nodes,
  showSearchField: false,
  onNodeTap: (node) {
    print('Tapped: ${node.title}');
  },
)

With Initial Selection

SearchableTree(
  nodes: nodes,
  initialSelectedNodeId: '1-2',
  onNodeSelected: (node, isSelected) {
    print('Selected: ${node.title}');
  },
)

Parameters

Parameter Type Default Description
nodes List<TreeNode> required List of tree nodes to display
titleStyle TextStyle? null Custom style for node titles
searchFieldStyle TextStyle? null Custom style for search input text
searchDecoration InputDecoration? null Custom decoration for search field
expandIconColor Color? null Color for expand/collapse icons
indentation double? 24.0 Indentation width for each tree level
showExpandIcon bool true Whether to show expand/collapse icons
showSearchField bool true Whether to show the search input field
highlightSearchMatches bool true Whether to highlight search matches
highlightColor Color? Colors.yellow Color for search match highlights
selectedColor Color? null Color for selected node highlight
allowNodeSelection bool true Whether to allow node selection
onNodeTap void Function(TreeNode node)? null Callback when a node is tapped
onExpandToggle void Function(TreeNode node, bool isExpanded)? null Callback when node expand state changes
onNodeSelected void Function(TreeNode node, bool isSelected)? null Callback when a node is selected
onAddButtonTap VoidCallback? null Callback when add button is tapped
onNodeShowMenu void Function(TreeNode node, Offset position)? null Callback when node menu icon is tapped
initialSelectedNodeId String? null Initial selected node ID

TreeNode Class

TreeNode({
  required this.id,        // Unique identifier for the node
  required this.title,
  this.children = const [],
  this.data,               // Custom data you can attach to the node
  this.isExpanded = false,
});

Additional information

Platform Support

  • βœ… Android
  • βœ… iOS
  • βœ… Web
  • βœ… Windows
  • βœ… macOS
  • βœ… Linux

Libraries

searchable_tree